package com.neouton.crm.pm.service.impl;


import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.neouton.common.entity.ActivitiVO;
import com.neouton.common.util.*;
import com.neouton.crm.approval.entity.ApprovalLogVO;
import com.neouton.crm.approval.entity.ApprovalVO;
import com.neouton.crm.approval.service.IApprovalService;
import com.neouton.crm.dictionary.entity.DictionaryLookupItemVO;
import com.neouton.crm.dictionary.service.IDictionaryService;
import com.neouton.crm.enterprise.entity.EnterpriseVO;
import com.neouton.crm.entity.SysUserEntity;
import com.neouton.crm.payRecords.entity.PaymentRequest;
import com.neouton.crm.pm.entity.*;
import com.neouton.crm.pm.mapper.BrAndBmrMapper;
import com.neouton.crm.pm.service.BrAndBmrService;
import com.neouton.crm.sales.entity.SalesFileRelationVO;
import com.neouton.crm.transpondEmail.service.TranspondEmailService;
import com.neouton.email.EmailType;
import com.neouton.email.entity.EmailVO;
import com.neouton.email.feginService.SentMailFeginService;
import com.neouton.feginClient.FeginService;
import com.neouton.feginClient.WorkFlowFeginService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 开票记录
 * 回款记录
 */
@Service
public class BrAndBmrServiceImpl implements BrAndBmrService {
    @Resource
    private WorkFlowFeginService workFlowFeginService;
    @Resource
    private BrAndBmrMapper brAndBmrMapper;
    @Resource
    private SentMailFeginService sentMailFeginService;
    @Resource
    private FeginService feginService;
    @Resource
    private IDictionaryService dictionaryService;
    @Resource
    private IApprovalService approvalService;
    @Resource
    private TranspondEmailService transpondEmailService;

    @Value("${webSit.web}")
    private String webSitUrl;


    @Override
    public void updateBillApplyRecordType(BillingRecordVo billingRecordVo) {
        //修改开票申请表（表示开票申请已被记录）
        BillingRecordVo billingApply = new BillingRecordVo();
        billingApply.setBillingRecordId(billingRecordVo.getBillId());
        billingApply.setRecordType(billingRecordVo.getRecordType());
        brAndBmrMapper.updateBillApply(billingApply);
    }

    /**
     *逻辑删除开票申请、记录
     * @param id
     */
    @Override
    public void deleteBillingById(Integer id) {
        brAndBmrMapper.deleteBillingById(id);
        //修改开票申请关联开票记录
        brAndBmrMapper.updateBillingRecordBillId(id);
    }

    /**
     * 逻辑删除回款记录
     * @param id
     */
    @Override
    public void deleteBackMoneyRecordById(Integer id) {
        brAndBmrMapper.deleteBackMoneyRecordById(id);
    }

    @Override
    public void updateBackMoneyRecordAfterPass(BackMoneyRecordVo backMoneyRecordVo, String token) {
        // 将修改后的数据放入redis缓存
        Map<String,Object> projectInfoMap = new HashMap<>();
        projectInfoMap.put(backMoneyRecordVo.getBmrId().toString(),backMoneyRecordVo);
        feginService.setCacheInfo(Constants.CACHE_BACKMONEYRECORD + backMoneyRecordVo.getBmrId(),projectInfoMap,token);
    }

    @Override
    public BackMoneyRecordVo querybackMoneyRecordFromCache(int bmrId, String token) {
        String managerCacheKey = Constants.CACHE_BACKMONEYRECORD+bmrId;
        ResponseAPI cacheInfo = feginService.getCacheInfo(managerCacheKey,String.valueOf(bmrId), token);
        String jsonObject= JSON.toJSONString(cacheInfo.getResult());
        //将json转成需要的对象
        BackMoneyRecordVo backMoneyRecordVo = JSONObject.parseObject(jsonObject,BackMoneyRecordVo.class);
        return backMoneyRecordVo;
    }

    @Override
    public void updateBillingRecordAfterPass(BillingRecordVo billingRecordVo, String token) {
        // 将修改后的数据放入redis缓存
        Map<String,Object> projectInfoMap = new HashMap<>();
        projectInfoMap.put(billingRecordVo.getBillingRecordId().toString(),billingRecordVo);
        feginService.setCacheInfo(Constants.CACHE_BILLINGRECORD + billingRecordVo.getBillingRecordId(),projectInfoMap,token);
    }

    @Override
    public BillingApplyVo queryBillingApplyFromCache(int billingRecordId, String token) {
        String managerCacheKey = Constants.CACHE_BILLINGRECORD + billingRecordId;
        ResponseAPI cacheInfo = feginService.getCacheInfo(managerCacheKey,String.valueOf(billingRecordId), token);
        String jsonObject= JSON.toJSONString(cacheInfo.getResult());
        //将json转成需要的对象
        BillingApplyVo billingApplyVo = JSONObject.parseObject(jsonObject,BillingApplyVo.class);
        return billingApplyVo;
    }

    @Override
    public void updateBillingApplyAfterPass(BillingApplyVo billingApplyVo, String token) {
        // 将修改后的数据放入redis缓存
        Map<String,Object> projectInfoMap = new HashMap<>();
        projectInfoMap.put(billingApplyVo.getBillingRecordId().toString(),billingApplyVo);
        feginService.setCacheInfo(Constants.CACHE_BILLINGRECORD + billingApplyVo.getBillingRecordId(),projectInfoMap,token);
    }

    @Override
    public BillingRecordVo queryBillingRecordFromCache(int billingRecordId, String token) {
        String managerCacheKey = Constants.CACHE_BILLINGRECORD + billingRecordId;
        ResponseAPI cacheInfo = feginService.getCacheInfo(managerCacheKey,String.valueOf(billingRecordId), token);
        String jsonObject= JSON.toJSONString(cacheInfo.getResult());
        //将json转成需要的对象
        BillingRecordVo billingRecordVo = JSONObject.parseObject(jsonObject,BillingRecordVo.class);
        return billingRecordVo;
    }

    @Override
    public void updateBillingDetailTableAfterPass(List<BackBillingMoneyVo> backBillingMoneyVos, String token) {
        // 将修改后的数据放入redis缓存
        Map<String,Object> projectInfoMap = new HashMap<>();
        BillingApplyVo billingApplyVo = new BillingApplyVo();
        billingApplyVo.setBackBillingMoneyVos(backBillingMoneyVos);
        projectInfoMap.put(backBillingMoneyVos.get(0).getBillId().toString(),billingApplyVo);
        feginService.setCacheInfo(Constants.CACHE_BILLINGDETAILTABLE + backBillingMoneyVos.get(0).getBillId(),projectInfoMap,token);
    }

    @Override
    public List<BackBillingMoneyVo> queryBillingDetailTableFromCache(int billingRecordId, String token) {
        String managerCacheKey = Constants.CACHE_BILLINGDETAILTABLE + billingRecordId;
        ResponseAPI cacheInfo = feginService.getCacheInfo(managerCacheKey,String.valueOf(billingRecordId), token);
        String jsonObject= JSON.toJSONString(cacheInfo.getResult());
        //将json转成需要的对象
        BillingApplyVo billingApplyVo = JSONObject.parseObject(jsonObject,BillingApplyVo.class);
        if(billingApplyVo!=null){
            return billingApplyVo.getBackBillingMoneyVos();
        }
        return null;
    }

    @Override
    public void updateBackMoneyDetailTableAfterPass(List<BackBillingMoneyVo> backBillingMoneyVos, String token) {
        // 将修改后的数据放入redis缓存
        Map<String,Object> projectInfoMap = new HashMap<>();
        BackMoneyRecordVo backMoneyRecordVo = new BackMoneyRecordVo();
        backMoneyRecordVo.setBackBillingMoneyVos(backBillingMoneyVos);
        projectInfoMap.put(backBillingMoneyVos.get(0).getBackMoneyId().toString(),backMoneyRecordVo);
        feginService.setCacheInfo(Constants.CACHE_BACKMONEYDETAILTABLE + backBillingMoneyVos.get(0).getBackMoneyId(),projectInfoMap,token);
    }

    @Override
    public List<BackBillingMoneyVo> queryBackMoneyDetailTableFromCache(int bmrId, String token) {
        String managerCacheKey = Constants.CACHE_BACKMONEYDETAILTABLE + bmrId;
        ResponseAPI cacheInfo = feginService.getCacheInfo(managerCacheKey,String.valueOf(bmrId), token);
        String jsonObject= JSON.toJSONString(cacheInfo.getResult());
        //将json转成需要的对象
        BackMoneyRecordVo backMoneyRecordVo = JSONObject.parseObject(jsonObject,BackMoneyRecordVo.class);
        if(backMoneyRecordVo!=null){
            return backMoneyRecordVo.getBackBillingMoneyVos();
        }
        return null;
    }


    /**
     * 保存开票申请
     *
     * @param billingApplyVo
     * @return
     */
    @Override
    public Integer saveBillingApply(BillingApplyVo billingApplyVo, String token) {
        //1.发起工作流
        //1）获取下一审批人，商务
        //获取审批人
        SysUserEntity user = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        //调用工作流
        Integer businessId = this.startContractApproval();
        //2.记录本地审批数据
        //生成审批主表信息，日志信息
        ApprovalVO approval = approvalService.initApprovalAndLog(businessId, 26,billingApplyVo.getAskReason() , "",
                user.getUserId(), "");
        //更新/保存 开票申请
        BillingRecordVo billingRecordVo = new BillingRecordVo();
        billingRecordVo.setApprovalId(approval.getApprovalId());

        BeanUtils.copyProperties(billingApplyVo, billingRecordVo);
        billingRecordVo.setPeriod(billingApplyVo.getPeriod().stream().map(String::valueOf).collect(Collectors.joining(",")));

        //添加状态
        billingRecordVo.setRecordType(0);

        if (billingApplyVo.getBillingRecordId() != null) {
            //记录开票申请备份表
            brAndBmrMapper.backUpBillingApply(billingApplyVo.getBillingRecordId(),AuthUtils.getUserId());
            billingRecordVo.setApprovalId(approval.getApprovalId());
            brAndBmrMapper.updateBillApply(billingRecordVo);
            //添加回款计划申请金额
            //addBackMoneyPlanBillMoney(billingApplyVo);
            //保存转发人
            if(billingApplyVo.getSenderList() != null &&billingApplyVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : billingApplyVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }

        } else {
            //保存
            billingRecordVo.setApprovalId(approval.getApprovalId());
            brAndBmrMapper.saveBillingApply(billingRecordVo);
            //添加回款计划申请金额
            // addBackMoneyPlanBillMoney(billingApplyVo);
            if(billingApplyVo.getSenderList() != null &&  billingApplyVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : billingApplyVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }

        }
        //发送审批邮件
        //发送邮件
        if(AuthUtils.getUserAccount().equals(user.getAccount())){
            billingApplyVo.setApprovalId(approval.getApprovalId());
            //跳过第一步审批
            this.passbillingApply(billingApplyVo,token,true);
        }else{
            //获取合同名称
            ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingRecordVo.getContractId());
            String titel = "【系统通知】开票申请 - 流程单审批通知";
            String msg =  initContractEmailData(user.getLoginName(),
                    "您有一张新的开票申请审批需要处理",
                    approval.getApprovalCode(),
                    AuthUtils.getUserName(),
                    contractInfo.getContractTopic(),
                    contractInfo.getContractNo(),
                    billingRecordVo.getBillMoney(),
                    billingRecordVo.getPeriod());

           // CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(user.getEmail(),null,titel,msg,token));
            //调用通知接口生成待办通知
            Integer userId = AuthUtils.getUserId();
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(approval.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                    userId,0,26,user.getUserId(),token));
        }
        return billingRecordVo.getBillingRecordId();
    }


    /**
     * 通过开票申请
     * @param billingApplyVo
     * @param token
     * @return
     */
    @Override
    public Boolean passbillingApply(BillingApplyVo billingApplyVo, String token,Boolean auto) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(billingApplyVo.getApprovalId());

        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingApplyVo.getContractId());
        //获取当前所处节点
        ResponseAPI<ActivitiVO> processNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);

        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        String ccUser = null;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();
        if(billingApplyVo.getOpinion() == "" || billingApplyVo.getOpinion() == null){
            billingApplyVo.setOpinion("同意");
        }
        //记录审批日志
        if(auto){
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "系统判定跳过",billingApplyVo.getOpinion());
        }else{
            //记录日志
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "",billingApplyVo.getOpinion());
        }
        //判断是否为最后一个审批人
        if( "出纳".equals(processNodeNameAndCode.getResult().getName())){
            //审批通过
            workFlowFeginService.approvalProcessByBusinessId(activitiVO);
            user=askUser;
            workState = 1;
            todoUser = 0;
            titel = "【系统通知】开票申请 - 流程单审批通过通知";
            msg =  initContractEmailData1(user.getLoginName(),"您申请的开票申请审批已通过"
                    ,approval.getApprovalCode(), user.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingApplyVo.getBillMoney(),
                    billingApplyVo.getPeriod().stream().map(String::valueOf).collect(Collectors.joining(",")));
            ccUser = this.queryBillingApplyCC();
            approvalService.approved(null,billingApplyVo.getApprovalId());

            String emailUsers = transpondEmailService.selectTranspondEmailStr(billingApplyVo.getApprovalId());
            if(emailUsers != null && emailUsers!=""){
                ccUser = ccUser + ','+emailUsers;
            }
            //开启代办 、 邮件
            String finalCcUser = ccUser;
            SysUserEntity finalUser = user;
            CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingApplyVo.getApprovalId(),  approval.getCreateDataTime(),
                    approval.getCreator(),workState,26,todoUser,token));
        }else {
            //动态获取下一步审批人员以及流程，设置参数
            if("商务".equals(processNodeNameAndCode.getResult().getName())){
                user = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
                activitiVO.getCustomParams().put("finance",user.getAccount());
            }else if ("会计".equals(processNodeNameAndCode.getResult().getName())){
                user = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
                activitiVO.getCustomParams().put("afterSales",user.getAccount());
            }else if("售后".equals(processNodeNameAndCode.getResult().getName()))  {
                user = dictionaryService.queryMenuUserIdsByCode("chairman").get(0);
                activitiVO.getCustomParams().put("chairman",user.getAccount());
            }else if("董事长".equals(processNodeNameAndCode.getResult().getName()))  {
                user = dictionaryService.queryMenuUserIdsByCode("cashier").get(0);
                activitiVO.getCustomParams().put("cashier",user.getAccount());
            }
            //审批通过（使用动态入参传入下一审批人）
            workFlowFeginService.approvalProcessCustomUserByBusinessId(activitiVO);
            //获取下一节点
            ResponseAPI<ActivitiVO> nextProcessNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);
            if(nextProcessNodeNameAndCode.getResult().getAssignee().equals(processNodeNameAndCode.getResult().getAssignee())){ //记录日志
                //approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                  //      "系统判定跳过",billingApplyVo.getOpinion());
                this.passbillingApply(billingApplyVo,token,true);
            }else {
                workState = 0;
                todoUser = user.getUserId();
                titel = "【系统通知】开票申请 - 流程单审批通知";
                msg =  initContractEmailData(user.getLoginName(),
                        "您有一张新的开票申请审批需要处理",
                        approval.getApprovalCode(),
                        askUser.getLoginName(),
                        contractInfo.getContractTopic(),
                        contractInfo.getContractNo(),
                        billingApplyVo.getBillMoney(),
                        billingApplyVo.getPeriod().stream().map(String::valueOf).collect(Collectors.joining(","))
                        );
                approvalService.updateNextApproverByApprovalId(user.getUserId(),billingApplyVo.getApprovalId());
                //记录日志
                //approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                //        "",billingApplyVo.getOpinion());
                String finalCcUser = ccUser;
                SysUserEntity finalUser = user;
                //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
                CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingApplyVo.getApprovalId(),  approval.getCreateDataTime(),
                        approval.getCreator(),workState,26,todoUser,token));
            }
        }
        return true;
    }
    /**
     * 驳回开票申请
     * @param billingApplyVo
     * @param token
     * @return
     */
    @Override
    public Boolean rejectBillingApply(BillingApplyVo billingApplyVo, String token) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(billingApplyVo.getApprovalId());
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //删除流程实例
        workFlowFeginService.deleteInstance(activitiVO);

       /* List<ApprovalLogVO> approvalLogVOS = approvalService.queryApprovalLogByAppID(approval.getApprovalId());
        //获取上一人
        ApprovalLogVO approvalLogVO = approvalLogVOS.get(approvalLogVOS.size() - 1);*/

        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();

        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingApplyVo.getContractId());

        /*SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        SysUserEntity afterSales = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
        SysUserEntity chairman = dictionaryService.queryMenuUserIdsByCode("chairman").get(0);
*/

        //if(AuthUtils.getUserId().equals(business.getUserId())){
            //workFlowFeginService.deleteInstance(activitiVO);
            user = askUser;
            //驳回至起点
            workState = 1;
            titel= "【系统通知】开票申请 - 流程单审批驳回通知";
            msg =  initContractEmailData2(askUser.getLoginName(),"您的开票申请审批已被驳回"
                    ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingApplyVo.getBillMoney(),
                    billingApplyVo.getPeriod().stream().map(String::valueOf).collect(Collectors.joining(",")),billingApplyVo.getOpinion());
            approvalService.approvalRejection(null,billingApplyVo.getApprovalId());
            todoUser = 0;
            //驳回时修改回款计划申请金额
            //updateBackmoneyPlanBillMoney(billingApplyVo);
            //驳回时 删除关系表中数据，将数据备份到备份表中
            backupBBM(billingApplyVo.getApprovalId(),AuthUtils.getUserId());

        /*}else {
            if(AuthUtils.getUserId().equals(finance.getUserId())){
                user = business;
            }else if (AuthUtils.getUserId().equals(afterSales.getUserId())){
                user = finance;
            }else  {
                user = afterSales;
            }
            //驳回至上一节点
            workFlowFeginService.rejectedByBusinessId(activitiVO);
            workState = 0;
            titel = "【系统通知】开票申请审批驳回通知";
            msg =  initContractEmailData(user.getLoginName(),"您有一张新的开票申请审批已被上级驳回，需要处理"
                    ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingApplyVo.getBillMoney(),
                    billingApplyVo.getPeriod().stream().map(String::valueOf).collect(Collectors.joining(",")));
            todoUser = user.getUserId();
            approvalService.updateNextApproverByApprovalId(user.getUserId(),billingApplyVo.getApprovalId());
        }*/
        //记录日志
        approvalService.insertApprovalLog(approval.getApprovalId(),"驳回",
                "",billingApplyVo.getOpinion());
        SysUserEntity finalUser = user;
        //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(),null,titel,msg,token));
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingApplyVo.getApprovalId(),  approval.getCreateDataTime(),
                approval.getCreator(),workState,26,todoUser,token));
        return true;
    }

    private void backupBBM(Integer approvalId, Integer backUserId){
        //备份
        brAndBmrMapper.backupBackBillingMoney(approvalId,backUserId);
        //删除关系表
        brAndBmrMapper.deleteBackBillingMoneyByApprovalId(approvalId);
    }


    /*private void updateBackmoneyPlanBillMoney(BillingApplyVo billingApplyVo) {
        //驳回时修改回款计划申请金额
        List<Integer> period = billingApplyVo.getPeriod();
        Integer lastPeriod = period.get(period.size() - 1);
        Integer lastPeriod1 = period.get(0);
        //计算出最后一期申请金额
        String billMoneyLast = brAndBmrMapper.getBackMoneyPlanByContractIdAndPeriod(billingApplyVo.getContractId(), lastPeriod).getBillMoney();
        String billMoneyFast = brAndBmrMapper.getBackMoneyPlanByContractIdAndPeriod(billingApplyVo.getContractId(), lastPeriod1).getBillMoney();
        String billMoney;
        //回款计划中减去申请金额
        if (period.size()>2){
            //多期次添加申请金额
            //更具合同id 和 期次 修改除lastPeriod期次外的其他期次申请金额（申请金额改为0）
            period.remove(0);
            for (Integer integer : period) {
                brAndBmrMapper.updateBackMonryPlanBillMoneyByLastPeriod(billingApplyVo.getContractId(),integer,"0.00");
            }
            //计算lastPeriod期次对应的申请金额
            List<String> list = brAndBmrMapper.getbmpMoney(billingApplyVo.getProjectManageId(), billingApplyVo.getContractId(), period);
            List<BigDecimal> decimalList = list.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            BigDecimal reduce = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal bigDecimal = new BigDecimal(billingApplyVo.getBillMoney());
            BigDecimal bigDecimalLast = new BigDecimal(billMoneyLast);
            BigDecimal bigDecimalFast = new BigDecimal(billMoneyFast);
            billMoney = bigDecimalFast.subtract(bigDecimal.subtract(reduce).subtract(bigDecimalLast)).toString();
        }else if (period.size() == 2){
            brAndBmrMapper.updateBackMonryPlanBillMoneyByLastPeriod(billingApplyVo.getContractId(),lastPeriod,"0.00");
            BigDecimal bigDecimal = new BigDecimal(billingApplyVo.getBillMoney());
            BigDecimal bigDecimalLast = new BigDecimal(billMoneyLast);
            BigDecimal bigDecimalFast = new BigDecimal(billMoneyFast);
            billMoney = bigDecimalFast.subtract(bigDecimal.subtract(bigDecimalLast)).toString();

        } else{
            //单期次驳回
            BigDecimal bigDecimalFast = new BigDecimal(billMoneyFast);
            BigDecimal bigDecimal = new BigDecimal(billingApplyVo.getBillMoney());
            billMoney = bigDecimalFast.subtract(bigDecimal).toString();
        }
        brAndBmrMapper.updateBackMonryPlanBillMoneyByLastPeriod(billingApplyVo.getContractId(),lastPeriod1,billMoney);
    }*/

    /**
     * 开启开票申请审批流程
     *
     * @return
     */
    private Integer startContractApproval() {
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("开票申请流程");
        activitiVO.setProcessCode("billingApply_flow");
        HashMap<String, Object> customParams = new HashMap<>();
        //商务审批
        SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        customParams.put("commercialSpecialist", business.getAccount());

        activitiVO.setCustomParams(customParams);
        ResponseAPI<ActivitiVO> responseAPI = workFlowFeginService.startProcessByDesignCodeVersionBatchCustomParams(activitiVO);
        return responseAPI.getResult().getBusinessId();
    }
    /**
     * 开启开票记录审批流程
     *
     * @return
     */
    private Integer startBillingRecordApproval() {
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("开票记录审批流程");
        activitiVO.setProcessCode("billingRecord_flow");
        HashMap<String, Object> customParams = new HashMap<>();
        //会计审批
        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        customParams.put("finance", finance.getAccount());

        activitiVO.setCustomParams(customParams);
        ResponseAPI<ActivitiVO> responseAPI = workFlowFeginService.startProcessByDesignCodeVersionBatchCustomParams(activitiVO);
        return responseAPI.getResult().getBusinessId();
    }

    /**
     * 开启回款记录审批流程
     *
     * @return
     */
    private Integer startBackMoneyRecordApproval() {
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        activitiVO.setProcessName("回款记录审批流程");
        activitiVO.setProcessCode("backMoneyRecord_flow");
        HashMap<String, Object> customParams = new HashMap<>();
        //商务审批
        SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        customParams.put("commercialSpecialist", business.getAccount());

        activitiVO.setCustomParams(customParams);
        ResponseAPI<ActivitiVO> responseAPI = workFlowFeginService.startProcessByDesignCodeVersionBatchCustomParams(activitiVO);
        return responseAPI.getResult().getBusinessId();
    }


    /**
     * 获取该项目中的开票申请(state表示通过或者不通过)
     *
     * @param id
     * @param state
     * @return
     */
    @Override
    public List<BillingRecordVo> getAllBillingApplyPeridName(Integer id, Integer billState, Integer state) {
        return brAndBmrMapper.getAllBillingApplyPeridName(id, billState, state);
    }

    @Override
    public BillingApplyVo searchBillingApplyByApprovalId(Integer approvalId) {
        BillingApplyVo billingApplyVo = new BillingApplyVo();
        Boolean aBoolean = brAndBmrMapper.judApprovalIdExists(approvalId);
        if (aBoolean != null ){
            BillingApplyDto billingApplyDto = brAndBmrMapper.searchBillingApplyByApprovalId(approvalId);
            BeanUtils.copyProperties(billingApplyDto,billingApplyVo);
            String[] split = billingApplyDto.getPeriod().split(",");
            List<Integer> list = new ArrayList<>();
            for (String item : split) {
                list.add(Integer.valueOf(item));
            }
            billingApplyVo.setPeriod(list);
        }else{
            BillingApplyDto billingApplyDto = brAndBmrMapper.searchBillingApplyBackByApprovalId(approvalId);
            BeanUtils.copyProperties(billingApplyDto,billingApplyVo);
            String[] split = billingApplyDto.getPeriod().split(",");
            List<Integer> list = new ArrayList<>();
            for (String item : split) {
                list.add(Integer.valueOf(item));
            }
            billingApplyVo.setPeriod(list);
        }

        return billingApplyVo;
    }

    @Override
    public BillingRecordVo searchBillingRecordByApprovalId(Integer approvalId) {
        Boolean aBoolean = brAndBmrMapper.judApprovalIdExists(approvalId);
        if (aBoolean != null ){
            return brAndBmrMapper.searchBillingRecordByApprovalId(approvalId);
        }else{
            return brAndBmrMapper.searchBillingRecordBackByApprovalId(approvalId);
        }
    }

    /**
     * 根据approvalId 查询 回款记录页面
     * @param approvalId
     * @return
     */
    @Override
    public BackMoneyRecordVo searchBackMoneyRecordByApprovalId(Integer approvalId) {
        Boolean aBoolean =  brAndBmrMapper.jubBmRecordExists(approvalId);
        if (aBoolean != null ){
            return brAndBmrMapper.searchBackMoneyRecordByApprovalId(approvalId);
        }else{
            return brAndBmrMapper.searchBackRecordBackByApprovalId(approvalId);
        }

    }

    /**
     * 通过开票记录
     * @param billingRecordVo
     * @param token
     * @return
     */
    @Override
    public Boolean passBillingRecord(BillingRecordVo billingRecordVo, String token,Boolean auto) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(billingRecordVo.getApprovalId());

        //获取不同审批人信息
        SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        //最终审批人
        SysUserEntity afterSales = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);

        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingRecordVo.getContractId());
        //获取当前所处节点
        ResponseAPI<ActivitiVO> processNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);

        if(billingRecordVo.getOpinion() == "" || billingRecordVo.getOpinion() == null){
            billingRecordVo.setOpinion("同意");
        }
        if (auto){
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "系统判定跳过",billingRecordVo.getOpinion());
        }else{
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "",billingRecordVo.getOpinion());
        }

        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        String ccUser = null;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();
        if( "会计".equals(processNodeNameAndCode.getResult().getName()) ){

            //修改开票申请表（表示开票申请已被记录）
            BillingRecordVo billingApply = new BillingRecordVo();
            billingApply.setBillingRecordId(billingRecordVo.getBillId());
            billingApply.setRecordType(4);
            brAndBmrMapper.updateBillApply(billingApply);


            workFlowFeginService.approvalProcessByBusinessId(activitiVO);
            user=askUser;
            workState = 1;
            todoUser = 0;
            titel = "【系统通知】开票记录 - 流程单审批通过通知";
            msg =  billingRecordEmailData1(user.getLoginName(),"您申请的开票记录审批已通过"
                    ,approval.getApprovalCode(), user.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingRecordVo.getBillMoney(),
                    billingRecordVo.getPeriod());
            ccUser = this.queryBillingRecordCC();
            approvalService.approved(null,billingRecordVo.getApprovalId());
            //记录日志
//            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
//                    "",billingRecordVo.getOpinion());
            String emailUsers = transpondEmailService.selectTranspondEmailStr(billingRecordVo.getApprovalId());
            if(emailUsers != null && emailUsers!=""){
                ccUser = ccUser + ','+emailUsers;
            }
            String finalCcUser = ccUser;
            SysUserEntity finalUser = user;
            CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingRecordVo.getApprovalId(),  approval.getCreateDataTime(),
                    approval.getCreator(),workState,28,todoUser,token));
            //返填回款计划开票信息
            Integer approvalId = billingRecordVo.getApprovalId();
            List<BackBillingMoneyVo> backBillingMoneys = brAndBmrMapper.getBackBillingMoneyByApprovalId(approvalId);
            for (BackBillingMoneyVo backBillingMoney : backBillingMoneys){
                Integer bmpId = backBillingMoney.getBmpId();
                //获取bmp信息
                BackMoneyPlanVo backMoneyPlan = brAndBmrMapper.getBackMoneyPlanBackByBmpId(bmpId);
                if(Double.parseDouble(backMoneyPlan.getBmpMoney())== Double.parseDouble(backBillingMoney.getMoney())){
                    backMoneyPlan.setIsBilling(1);
                }else if(Double.parseDouble(backBillingMoney.getMoney()) < Double.parseDouble(backMoneyPlan.getBmpMoney())
                        && Double.parseDouble(backBillingMoney.getMoney()) > 0){
                    backMoneyPlan.setIsBilling(2);
                }else {
                    backMoneyPlan.setIsBilling(0);
                }
                brAndBmrMapper.updateBmpIsbilling(backMoneyPlan);
            }
        }
//        else {
//           if ("会计".equals(processNodeNameAndCode.getResult().getName())){
//                user = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
//                activitiVO.getCustomParams().put("afterSales",user.getAccount());
//            }
//            //审批通过（使用动态入参传入下一审批人）
//            workFlowFeginService.approvalProcessCustomUserByBusinessId(activitiVO);
//            //获取下一节点
//            ResponseAPI<ActivitiVO> nextProcessNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);
//            if(nextProcessNodeNameAndCode.getResult().getAssignee().equals(processNodeNameAndCode.getResult().getAssignee())){ //记录日志
////                approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
////                        "系统判定跳过",billingRecordVo.getOpinion());
//                this.passBillingRecord(billingRecordVo,token,true);
//            }else {
//                workState = 0;
//                todoUser = user.getUserId();
//                titel = "【系统通知】开票记录 - 流程单审批通知";
//                msg =  billingRecordEmailData(user.getLoginName(),"您有一张新的开票记录审批需要处理"
//                        ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic()
//                        ,contractInfo.getContractNo(),billingRecordVo.getBillMoney(),
//                        billingRecordVo.getPeriod());
//                approvalService.updateNextApproverByApprovalId(user.getUserId(),billingRecordVo.getApprovalId());
//                //记录日志
////                approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
////                        "",billingRecordVo.getOpinion());
//                String finalCcUser = ccUser;
//                SysUserEntity finalUser = user;
//                //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
//                CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingRecordVo.getApprovalId(),  approval.getCreateDataTime(),
//                        approval.getCreator(),workState,28,todoUser,token));
//            }
//        }
        return true;
    }

    /**
     * 驳回开票记录
     * @param billingRecordVo
     * @param token
     * @return
     */
    @Override
    public Boolean rejectBillingRecord(BillingRecordVo billingRecordVo, String token) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(billingRecordVo.getApprovalId());
        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //删除流程实例
        workFlowFeginService.deleteInstance(activitiVO);

        //修改开票申请表（表示开票申请已被记录）
        BillingRecordVo billingApply = new BillingRecordVo();
        billingApply.setBillingRecordId(billingRecordVo.getBillId());
        billingApply.setRecordType(3);
        brAndBmrMapper.updateBillApply(billingApply);


        /*List<ApprovalLogVO> approvalLogVOS = approvalService.queryApprovalLogByAppID(approval.getApprovalId());
        //获取上一人
        ApprovalLogVO approvalLogVO = approvalLogVOS.get(approvalLogVOS.size() - 1);*/
        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();

        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingRecordVo.getContractId());

       /* SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        SysUserEntity afterSales = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);*/


       // if(AuthUtils.getUserId().equals(business.getUserId())){
            //workFlowFeginService.deleteInstance(activitiVO);
            user = askUser;
            //驳回至起点
            workState = 1;
            titel= "【系统通知】开票记录 - 流程单审批驳回通知";
            msg =  billingRecordEmailData2(askUser.getLoginName(),"您的开票记录审批已被驳回"
                    ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingRecordVo.getBillMoney(),
                    billingRecordVo.getPeriod(),billingRecordVo.getOpinion());
            approvalService.approvalRejection(null,billingRecordVo.getApprovalId());
            todoUser = 0;
            backupBBM(billingRecordVo.getApprovalId(),AuthUtils.getUserId());
        /*}else {
            //驳回至上一节点
            if(AuthUtils.getUserId().equals(finance.getUserId())){
                user = business;
            }else {
                user = finance;
            }

            workFlowFeginService.rejectedByBusinessId(activitiVO);
            workState = 0;
            titel = "【系统通知】开票记录审批驳回通知";
            msg =  billingRecordEmailData(user.getLoginName(),"您有一张新的开票记录审批已被上级驳回，需要处理"
                    ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingRecordVo.getBillMoney(),
                    billingRecordVo.getPeriod());
            todoUser = user.getUserId();
            approvalService.updateNextApproverByApprovalId(user.getUserId(),billingRecordVo.getApprovalId());
        }*/
        //记录日志
        approvalService.insertApprovalLog(approval.getApprovalId(),"驳回",
                "",billingRecordVo.getOpinion());
        SysUserEntity finalUser = user;
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(),null,titel,msg,token));
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(billingRecordVo.getApprovalId(),  approval.getCreateDataTime(),
                approval.getCreator(),workState,28,todoUser,token));
        return true;
    }



    /**
     * 通过回款记录
     * @param backMoneyRecordVo
     * @param token
     * @return
     */
    @Override
    public Boolean passBackMoneyRecord(BackMoneyRecordVo backMoneyRecordVo, String token,Boolean auto) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(backMoneyRecordVo.getApprovalId());

        //获取不同审批人信息
        SysUserEntity business = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        SysUserEntity finance = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        //最终审批人
        SysUserEntity afterSales = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);

        ActivitiVO activitiVO = new ActivitiVO();//最终审批人
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyRecordVo.getContractId());
        //获取当前所处节点
        ResponseAPI<ActivitiVO> processNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);

        if(backMoneyRecordVo.getOpinion() == "" || backMoneyRecordVo.getOpinion() == null){
            backMoneyRecordVo.setOpinion("同意");
        }


        if(auto){
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "系统判定跳过",backMoneyRecordVo.getOpinion());
        }else{
            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
                    "",backMoneyRecordVo.getOpinion());
        }

        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        String ccUser = null;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();
        if(  "出纳".equals(processNodeNameAndCode.getResult().getName())){
            //修改开票记录回款状态 1表示通过
            updateBillingAndBackMoneyIsbm(backMoneyRecordVo.getBillId(),1);

            //审批通过
            workFlowFeginService.approvalProcessByBusinessId(activitiVO);
            user=askUser;
            workState = 1;
            todoUser = 0;
            titel = "【系统通知】回款记录 - 流程单审批通过通知";
            msg =  backMoneyRecordEmailData1(user.getLoginName(),"您申请的回款记录审批已通过"
                    ,approval.getApprovalCode(), user.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),backMoneyRecordVo.getBmrMoney(),
                    backMoneyRecordVo.getBmrPeriod());
            ccUser = this.queryBackMoneyRecordCC();
            approvalService.approved(null,backMoneyRecordVo.getApprovalId());
//            approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
//                    "",backMoneyRecordVo.getOpinion());
            String emailUsers = transpondEmailService.selectTranspondEmailStr(backMoneyRecordVo.getApprovalId());
            if(emailUsers != null && emailUsers!=""){
                ccUser = ccUser + ','+emailUsers;
            }
            String finalCcUser = ccUser;
            SysUserEntity finalUser = user;
            CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(backMoneyRecordVo.getApprovalId(),  approval.getCreateDataTime(),
                    approval.getCreator(),workState,29,todoUser,token));
        }else {
            if("商务".equals(processNodeNameAndCode.getResult().getName())){
                user = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
                activitiVO.getCustomParams().put("finance",user.getAccount());
            }else if ("会计".equals(processNodeNameAndCode.getResult().getName())){
                user = dictionaryService.queryMenuUserIdsByCode("afterSales").get(0);
                activitiVO.getCustomParams().put("afterSales",user.getAccount());
            }else if ("售后".equals(processNodeNameAndCode.getResult().getName())){
                user = dictionaryService.queryMenuUserIdsByCode("cashier").get(0);
                activitiVO.getCustomParams().put("cashier",user.getAccount());
            }
            //审批通过（使用动态入参传入下一审批人）
            workFlowFeginService.approvalProcessCustomUserByBusinessId(activitiVO);
            //获取下一节点
            ResponseAPI<ActivitiVO> nextProcessNodeNameAndCode = workFlowFeginService.getProcessNodeNameAndCode(activitiVO);
            if(nextProcessNodeNameAndCode.getResult().getAssignee().equals(processNodeNameAndCode.getResult().getAssignee())){ //记录日志
//                approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
//                        "系统判定跳过",backMoneyRecordVo.getOpinion());
                this.passBackMoneyRecord(backMoneyRecordVo,token,true);
            }else {
                workState = 0;
                todoUser = user.getUserId();
                titel = "【系统通知】回款记录 - 流程单审批通知";
                msg =  backMoneyRecordEmailData(user.getLoginName(),"您有一张新的回款记录审批需要处理"
                        ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic()
                        ,contractInfo.getContractNo(),backMoneyRecordVo.getBmrMoney(),
                        backMoneyRecordVo.getBmrPeriod());
                approvalService.updateNextApproverByApprovalId(user.getUserId(),backMoneyRecordVo.getApprovalId());
                //记录日志
//                approvalService.insertApprovalLog(approval.getApprovalId(),"通过",
//                        "",backMoneyRecordVo.getOpinion());
                String finalCcUser = ccUser;
                SysUserEntity finalUser = user;
                //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(), finalCcUser,titel,msg,token));
                CompletableFuture.runAsync(() -> NoticUtils.pushNotic(backMoneyRecordVo.getApprovalId(),  approval.getCreateDataTime(),
                        approval.getCreator(),workState,29,todoUser,token));

            }
        }
        return true;
    }

    /**
     * 驳回回款记录
     * @param backMoneyRecordVo
     * @param token
     * @return
     */
    @Override
    public Boolean rejectBackMoneyRecord(BackMoneyRecordVo backMoneyRecordVo, String token) {
        //获取工作流ID
        ApprovalVO approval = approvalService.queryApprovalByAppID(backMoneyRecordVo.getApprovalId());

        ActivitiVO activitiVO = new ActivitiVO();
        activitiVO.setBusinessId(approval.getBusinessId());
        //认证
        activitiVO.setAuthorization(AuthUtils.getUserAccount());
        //删除流程实例
        workFlowFeginService.deleteInstance(activitiVO);
        //修改开票记录 回款状态
        updateBillingAndBackMoneyIsbm(backMoneyRecordVo.getBillId(),0);

        SysUserEntity user = null;
        Integer workState;
        String titel;
        String msg;
        Integer todoUser;
        SysUserEntity askUser = feginService.searchUserInfoById(approval.getCreator(), token).getResult();
        //获取合同名称
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyRecordVo.getContractId());

            user = askUser;
            workFlowFeginService.deleteInstance(activitiVO);
            //驳回至起点
            workState = 1;
            titel= "【系统通知】回款记录 - 流程单审批驳回通知";
            msg =  backMoneyRecordEmailData2(askUser.getLoginName(),"您的回款记录审批已被驳回"
                    ,approval.getApprovalCode(), askUser.getLoginName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),backMoneyRecordVo.getBmrMoney(),
                    backMoneyRecordVo.getBmrPeriod(),backMoneyRecordVo.getOpinion());
            approvalService.approvalRejection(null,backMoneyRecordVo.getApprovalId());
            todoUser = 0;
            backupBBM(backMoneyRecordVo.getApprovalId(),AuthUtils.getUserId());

        //记录日志
        approvalService.insertApprovalLog(approval.getApprovalId(),"驳回",
                "",backMoneyRecordVo.getOpinion());
        SysUserEntity finalUser = user;
        CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(finalUser.getEmail(),null,titel,msg,token));
        CompletableFuture.runAsync(() -> NoticUtils.pushNotic(backMoneyRecordVo.getApprovalId(),  approval.getCreateDataTime(),
                approval.getCreator(),workState,29,todoUser,token));
        return true;
    }

    /**
     * 查询合同是否通过
     * @param contractId
     * @return
     */
    @Override
    public ContractInfoVO ContractApplyPassOrNOByContractId(Integer contractId) {
        return brAndBmrMapper.ContractApplyPassOrNOByContractId(contractId);
    }

    /**
     * 保存开票记录
     *
     * @param billingRecordVo
     */
    @Override
    public Integer saveBillingRecord(BillingRecordVo billingRecordVo, String token) {
        //1.发起工作流
        //获取审批人
        SysUserEntity user = dictionaryService.queryMenuUserIdsByCode("finance").get(0);
        //调用工作流
        Integer businessId = this.startBillingRecordApproval();
        //2.记录本地审批数据
        //生成审批主表信息，日志信息
        ApprovalVO approval = approvalService.initApprovalAndLog(businessId, 28, billingRecordVo.getAskReason(), "",
                user.getUserId(), "");
        billingRecordVo.setApprovalId(approval.getApprovalId());


        if (billingRecordVo.getBillingRecordId() != null) {
            //billingRecordVo.setApprovalId(approval.getApprovalId());
            //记录开票记录备份表
            brAndBmrMapper.backUpBillingReord(billingRecordVo.getBillingRecordId(),AuthUtils.getUserId());
            brAndBmrMapper.updateBillingRecord(billingRecordVo);
            //修改开票申请表（表示开票申请已被记录）
            BillingRecordVo billingApply = new BillingRecordVo();
            billingApply.setBillingRecordId(billingRecordVo.getBillId());
            billingApply.setBillId(billingRecordVo.getBillingRecordId());
            billingApply.setRecordType(1);
            brAndBmrMapper.updateBillApply(billingApply);
            //修改开票申请表（表示开票申请已被记录）
            //保存转发人
            if(billingRecordVo.getSenderList() != null &&billingRecordVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : billingRecordVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }
        } else {
            //billingRecordVo.setApprovalId(approval.getApprovalId());
            brAndBmrMapper.saveBillingRecord(billingRecordVo);


            //保存转发人
            if(billingRecordVo.getSenderList() != null &&billingRecordVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : billingRecordVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }
            //修改开票申请表（表示开票申请已被记录）
            BillingRecordVo billingApply = new BillingRecordVo();
            billingApply.setBillingRecordId(billingRecordVo.getBillId());
            billingApply.setBillId(billingRecordVo.getBillingRecordId());
            billingApply.setRecordType(1);
            brAndBmrMapper.updateBillApply(billingApply);
        }

        if(AuthUtils.getUserAccount().equals(user.getAccount())){
            //跳过第一步审批
            this.passBillingRecord(billingRecordVo,token,true);
        }else {
            //发送审批邮件
            //发送邮件
            //获取合同名称
            ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(billingRecordVo.getContractId());

//            String titel = "【系统通知】开票记录 - 流程单审批通知";
//            String msg =  billingRecordEmailData(user.getLoginName(),"您有一张新的开票记录审批需要处理",approval.getApprovalCode(),
//                    AuthUtils.getUserName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),billingRecordVo.getBillMoney(),
//                    billingRecordVo.getPeriod());
            //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(user.getEmail(),null,titel,msg,token));
            //调用通知接口生成待办通知
            Integer userId = AuthUtils.getUserId();
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(approval.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                    userId,0,28,user.getUserId(),token));

        }
        return billingRecordVo.getBillingRecordId();
    }

    /**
     * 获取该项目中所有开票记录 / 开票申请
     *
     * @param id
     * @return
     */
    @Override
    public List<ContractInfoVO> getProjectAllBillingRecord(Integer id, Integer billState) {
        return brAndBmrMapper.getProjectAllBillingRecord(id, billState);
    }

    /**
     * 保存回款记录
     *
     * @param backMoneyRecordVo
     */
    @Override
    public Integer saveBackMoneyRecord(BackMoneyRecordVo backMoneyRecordVo,String token) {
        //1.发起工作流
        //1）获取下一审批人，暂定总经理
        //获取审批人
        SysUserEntity user = dictionaryService.queryMenuUserIdsByCode("commercialSpecialist").get(0);
        //调用工作流
        Integer businessId = this.startBackMoneyRecordApproval();
        //2.记录本地审批数据
        //生成审批主表信息，日志信息
        ApprovalVO approval = approvalService.initApprovalAndLog(businessId, 29, backMoneyRecordVo.getAskReason(), "",
                user.getUserId(), "");
        backMoneyRecordVo.setApprovalId(approval.getApprovalId());

        if (backMoneyRecordVo.getBmrId() != null) {
            //backMoneyRecordVo.setApprovalId(approval.getApprovalId());
            //记录回款记录备份表
            brAndBmrMapper.backupBackMoneyRecord(backMoneyRecordVo.getBmrId(),AuthUtils.getUserId());
            brAndBmrMapper.updateBackMoneyRecord(backMoneyRecordVo);
            //保存转发人
            if(backMoneyRecordVo.getSenderList() != null &&backMoneyRecordVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : backMoneyRecordVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }
        } else {
            //backMoneyRecordVo.setApprovalId(approval.getApprovalId());
            brAndBmrMapper.saveBackMoneyRecord(backMoneyRecordVo);
            //保存转发人
            if(backMoneyRecordVo.getSenderList() != null &&backMoneyRecordVo.getSenderList().size() > 0){
                ArrayList<SysUserEntity> userList = new ArrayList<>();
                for (Integer userId : backMoneyRecordVo.getSenderList()) {
                    SysUserEntity sysUserEntity = new SysUserEntity() ;
                    sysUserEntity.setUserId(userId);
                    userList.add(sysUserEntity);
                }
                //保存转发人
                transpondEmailService.insertTranspondEmailInfoByUser(approval.getApprovalId(),userList);
            }
        }

        if(AuthUtils.getUserAccount().equals(user.getAccount())){
            //跳过第一步审批
            this.passBackMoneyRecord(backMoneyRecordVo,token,true);
        }else {
            //发送审批邮件
            //发送邮件

            //获取合同名称
            ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyRecordVo.getContractId());

            String titel = "【系统通知】回款记录 - 流程单审批通知";
            String msg =  backMoneyRecordEmailData(user.getLoginName(),"您有一张新的回款记录审批需要处理",approval.getApprovalCode(),
                    AuthUtils.getUserName(),contractInfo.getContractTopic(),contractInfo.getContractNo(),backMoneyRecordVo.getBmrMoney(),
                    backMoneyRecordVo.getBmrPeriod());
            //CompletableFuture.runAsync(() -> EmailUtils.sentMailByAddressee(user.getEmail(),null,titel,msg,token));
            //调用通知接口生成待办通知
            Integer userId = AuthUtils.getUserId();
            CompletableFuture.runAsync(() -> NoticUtils.pushNotic(approval.getApprovalId(), new Timestamp(System.currentTimeMillis()),
                    userId,0,29,user.getUserId(),token));

        }
        return backMoneyRecordVo.getBmrId();
    }

    /**
     * 获取该项目中所有开票记录
     *
     * @param id
     * @return
     */
    @Override
    public List<ContractInfoVO> getProjectAllBackMoneyRecord(Integer id) {
        return brAndBmrMapper.getProjectAllBackMoneyRecord(id);
    }

    /**
     * 获取客户中所有开票记录
     *
     * @param customerId
     * @return
     */
    @Override
    public List<ContractInfoVO> getProjectAllBackMoneyRecordByCustomerId(Integer customerId) {
        return brAndBmrMapper.getProjectAllBackMoneyRecordByCustomerId(customerId);
    }


    /**
     * 开票页面金额显示
     *
     * @param projectManageId
     * @param contractId
     * @param period
     * @return
     */
    @Override
    public ShowMoneyVo getShowMoney(Integer projectManageId, Integer contractId, List<Integer> period) {
        ShowMoneyVo showMoneyVo = new ShowMoneyVo();
        //获取计划金额的和
        List<String> bmpMoneylist = brAndBmrMapper.getbmpMoney(projectManageId, contractId, period);
        List<BigDecimal> decimalList = bmpMoneylist.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
        String bmpMoney = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();

        //获取已申请开票金额
        List<String> billMoneyList = brAndBmrMapper.getbillMoney(projectManageId, contractId, period);
        List<BigDecimal> billMoneyCollect = billMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
        String receiveMoney = billMoneyCollect.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();

        //计算剩余金额
        String residualMoney = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add).subtract(billMoneyCollect.stream().reduce(BigDecimal.ZERO, BigDecimal::add)).toString();
        String minBillMoney;
        //多期次时 计算最小开票金额
        if (period.size() > 1){
            period.remove(period.size()-1);
            List<String> billMList = brAndBmrMapper.getbmpMoney(projectManageId, contractId, period);
            List<BigDecimal> billMcollect = billMList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            String billMoneyFast = brAndBmrMapper.getBackMoneyPlanByContractIdAndPeriod(contractId, period.get(0)).getBillMoney();
            if (billMoneyFast != null){
                BigDecimal bigDecimal = new BigDecimal(billMoneyFast);
                minBillMoney = billMcollect.stream().reduce(BigDecimal.ZERO, BigDecimal::add).subtract(bigDecimal).toString();
            }else{
                minBillMoney = billMcollect.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();
            }
        }else{
             minBillMoney = null;
        }

        showMoneyVo.setBmpMoney(bmpMoney);
        showMoneyVo.setReceiveMoney(receiveMoney);
        showMoneyVo.setResidualMoney(residualMoney);
        showMoneyVo.setMinBillMoney(minBillMoney);
        return showMoneyVo;
    }

    /**
     * 回款记录页面金额显示
     *
     * @param projectManageId
     * @param contractId
     * @param period
     * @return
     */
    @Override
    public ShowMoneyVo getBmrShowMoney(Integer projectManageId, Integer contractId, List<Integer> period) {
        ShowMoneyVo showMoneyVo = new ShowMoneyVo();
        //获取计划金额
        /*List<String> bmpMoney = brAndBmrMapper.getbmpMoney(projectManageId, contractId, period);*/
        /*BigDecimal bmpMoneyShow = new BigDecimal(bmpMoney);
        bmpMoneyShow = bmpMoneyShow.setScale(2, RoundingMode.HALF_UP);
        //获取已回款金额
        List<String> receiveMoneyList = brAndBmrMapper.getBmrReceiveMoney(projectManageId, contractId, period);
        BigDecimal sumSreceiveMoney = new BigDecimal("0.00");
        for (String s : receiveMoneyList) {
            BigDecimal decimal = new BigDecimal(s);
            sumSreceiveMoney = sumSreceiveMoney.add(decimal);
        }
        //获取已开票金额
        List<String> backMoneyList = brAndBmrMapper.getreceiveMoney(projectManageId, contractId, period);
        BigDecimal reBackMoney = new BigDecimal("0.00");
        for (String s : backMoneyList) {
            BigDecimal decimal = new BigDecimal(s);
            reBackMoney = reBackMoney.add(decimal);
        }

        BigDecimal numResidualMoney = new BigDecimal(bmpMoney).subtract(sumSreceiveMoney);
        showMoneyVo.setReBackMoney(reBackMoney.toString());
        showMoneyVo.setBmpMoney(bmpMoneyShow.toString());
        showMoneyVo.setReceiveMoney(sumSreceiveMoney.toString());
        showMoneyVo.setResidualMoney(numResidualMoney.toString());*/
        return showMoneyVo;
    }

    /**
     * 获取附件
     *
     * @param salesRelationId
     * @param fileClass
     * @return
     */
    @Override
    public List<SalesFileRelationVO> getSalesByBillingRecordId(Integer salesRelationId, Integer fileClass) {
        return brAndBmrMapper.getSalesByBillingRecordId(salesRelationId, fileClass);
    }

    /**
     * 定时发布提醒邮件
     * 每天9点30分开启任务 发送邮件
     */
    @Override
    //@Scheduled(cron = "1 30 9 * * ?")
    public void timingPushHintEmail() {
        //查询所有计划 获取所有计划时间
        List<BackMoneyPlanVo> allBackMoneyPlan = brAndBmrMapper.getAllBackMoneyPlan();
        //查询所有回款记录(已经通过审批的)
        List<BackMoneyRecordVo> allBackMoneyRecord = brAndBmrMapper.getAllBackMoneyRecord();
        //筛选去除已经回款的
        if (allBackMoneyRecord.isEmpty() || allBackMoneyRecord.isEmpty()){
            return;
        }

        for (int i = 0; i < allBackMoneyPlan.size(); i++) {
            for (int j = 0; j < allBackMoneyRecord.size(); j++) {
                String bmrPeriod = allBackMoneyRecord.get(j).getBmrPeriod();
                String[] split = bmrPeriod.split(",");
                List<Integer> collect = Arrays.stream(split).map(Integer::valueOf).collect(Collectors.toList());
                boolean contains = collect.contains(allBackMoneyPlan.get(i).getBmpPeriod());

                if (allBackMoneyPlan.get(i).getProjectManageId() == allBackMoneyRecord.get(j).getProjectManageId()
                    && contains
                ) {
                    allBackMoneyPlan.remove(allBackMoneyPlan.get(i));
                    break;
                }
            }
        }
        //需要发送提醒邮件的 计划 ---allBackMoneyPlan
        //获取当前时间 nowTime当前时间毫秒值
        Date day = new Date();
        long nowTime = day.getTime();

        for (BackMoneyPlanVo backMoneyPlanVo : allBackMoneyPlan) {
            if ((backMoneyPlanVo.getBmpDate().getTime() - nowTime) < 30 * 24 * 60 * 60 * 1000 && (backMoneyPlanVo.getBmpDate().getTime() - nowTime) > 29 * 24 * 60 * 60 * 1000) {
                System.out.println("1111111");
                sendRemindEmail(backMoneyPlanVo);
            } else if ((backMoneyPlanVo.getBmpDate().getTime() - nowTime) < 7 * 24 * 60 * 60 * 1000 && (backMoneyPlanVo.getBmpDate().getTime() - nowTime) > 0) {
                System.out.println("22222222");
                sendUrgentEmail(backMoneyPlanVo);
            } else if ((backMoneyPlanVo.getBmpDate().getTime() - nowTime) < 0) {
                System.out.println("33333333");
                sendOverEmail(backMoneyPlanVo);
            }
        }
    }


    //发送30天提醒邮件
    private void sendRemindEmail(BackMoneyPlanVo backMoneyPlanVo) {
        EmailVO emailVO = new EmailVO();
        //获取责任人信息
        SysUserEntity liableInfo = brAndBmrMapper.getUserInfo(backMoneyPlanVo.getLiableId());
        //获取合同信息
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyPlanVo.getContractId());
        //获取项目信息
        SalesProjectManageVO projectManageInfo = brAndBmrMapper.getProjectManageInfoById(backMoneyPlanVo.getProjectManageId());
        //获取项目中客户信息
        EnterpriseVO enterpriseInfo = brAndBmrMapper.getEnterpriseInfoById(projectManageInfo.getCustomerId());
        //填写收件人的邮箱
        emailVO.setAddressee(liableInfo.getEmail());
        //获取抄送人邮箱
        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("projectManage");
        String userEmailStrings = getCopyForUserEmails(copyUserIList);
        //填写抄送人的邮箱
        emailVO.setCcUser(userEmailStrings);
        emailVO.setSubject("【系统通知】回款事项即将到期通知");
        String msg = "<div><p style='text-indent: 2em'>"
                + "尊敬的" + liableInfo.getLoginName() + "：</p></div>"
                + "<div><p style='text-indent: 4em'>您好，现有回款事项即将到期，请您注意！</p></div>"
                + "<div><p style='text-indent: 4em'>项目名称：" + projectManageInfo.getProjectTheme() + "</p></div>"
                + "<div><p style='text-indent: 4em'>项目编号：" + projectManageInfo.getProjectNumber() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同名称：" + contractInfo.getContractTopic() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同编号：" + contractInfo.getContractNo() + "</p></div>"
                + "<div><p style='text-indent: 4em'>客户名称：" + enterpriseInfo.getEnterpriseName() + "</p></div>"
                + "<div><p style='text-indent: 4em'>期次：第" + backMoneyPlanVo.getBmpPeriod() + "期次" + "</p></div>"
                + "<div><p style='text-indent: 2em'>请及时处理以上事项！如已回款请登录公司客户关系管理系统-项目信息-项目列表页面更新信息。</p></div> "
                + "<div><p style='text-indent: 2em'>谢谢！</p></div> "
                + "<div><p style='text-indent: 4em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        //邮件内容
        emailVO.setMailContent(msg);
        emailVO.setEmtilType(EmailType.EMAIL_TYPE_HTML);
        CompletableFuture.runAsync(() -> {
            sentMailFeginService.sentMail(emailVO);
        });
    }

    //发送7天内 紧急通知
    private void sendUrgentEmail(BackMoneyPlanVo backMoneyPlanVo) {
        EmailVO emailVO = new EmailVO();
        //获取责任人信息
        SysUserEntity liableInfo = brAndBmrMapper.getUserInfo(backMoneyPlanVo.getLiableId());
        //获取合同信息
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyPlanVo.getContractId());
        //获取项目信息
        SalesProjectManageVO projectManageInfo = brAndBmrMapper.getProjectManageInfoById(backMoneyPlanVo.getProjectManageId());
        //获取项目中客户信息
        EnterpriseVO enterpriseInfo = brAndBmrMapper.getEnterpriseInfoById(projectManageInfo.getCustomerId());
        //填写收件人的邮箱
        emailVO.setAddressee(liableInfo.getEmail());
        //获取抄送人邮箱
        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("projectManage");
        String userEmailStrings = getCopyForUserEmails(copyUserIList);
        //填写抄送人的邮箱
        emailVO.setCcUser(userEmailStrings);

        emailVO.setSubject("【系统通知】回款事项紧急通知");
        String msg = "<div><p style='text-indent: 2em'>"
                + "尊敬的" + liableInfo.getLoginName() + "：</p></div>"
                + "<div><p style='text-indent: 4em'>您好，现有回款事项一周内到期，请您注意！</p></div>"
                + "<div><p style='text-indent: 4em'>项目名称：" + projectManageInfo.getProjectTheme() + "</p></div>"
                + "<div><p style='text-indent: 4em'>项目编号：" + projectManageInfo.getProjectNumber() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同名称：" + contractInfo.getContractTopic() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同编号：" + contractInfo.getContractNo() + "</p></div>"
                + "<div><p style='text-indent: 4em'>客户名称：" + enterpriseInfo.getEnterpriseName() + "</p></div>"
                + "<div><p style='text-indent: 4em'>期次：第" + backMoneyPlanVo.getBmpPeriod() + "期次" + "</p></div>"
                + "<div><p style='text-indent: 2em'>请及时处理以上事项！如已回款请登录公司客户关系管理系统-项目信息-项目列表页面更新信息。</p></div> "
                + "<div><p style='text-indent: 2em'>谢谢！</p></div> "
                + "<div><p style='text-indent: 4em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        //邮件内容
        emailVO.setMailContent(msg);
        emailVO.setEmtilType(EmailType.EMAIL_TYPE_HTML);
        CompletableFuture.runAsync(() -> {
            sentMailFeginService.sentMail(emailVO);
        });
    }

    //发送逾期通知
    private void sendOverEmail(BackMoneyPlanVo backMoneyPlanVo) {
        EmailVO emailVO = new EmailVO();
        //获取责任人信息
        SysUserEntity liableInfo = brAndBmrMapper.getUserInfo(backMoneyPlanVo.getLiableId());
        //获取合同信息
        ContractInfoVO contractInfo = brAndBmrMapper.getContractInfoById(backMoneyPlanVo.getContractId());
        //获取项目信息
        SalesProjectManageVO projectManageInfo = brAndBmrMapper.getProjectManageInfoById(backMoneyPlanVo.getProjectManageId());
        //获取项目中客户信息
        EnterpriseVO enterpriseInfo = brAndBmrMapper.getEnterpriseInfoById(projectManageInfo.getCustomerId());
        //填写收件人的邮箱
        emailVO.setAddressee(liableInfo.getEmail());
        //获取抄送人邮箱
        List<SysUserEntity> copyUserIList = dictionaryService.queryCcUserIdsByCode("backMoneyRecordCC");
        String userEmailStrings = getCopyForUserEmails(copyUserIList);
        //填写抄送人的邮箱
        emailVO.setCcUser(userEmailStrings);

        emailVO.setSubject("【系统通知】回款事项逾期通知");
        String msg = "<div><p style='text-indent: 2em'>"
                + "尊敬的" + liableInfo.getLoginName() + "：</p></div>"
                + "<div><p style='text-indent: 4em'>您好，现有回款事项已逾期，请您注意！</p></div>"
                + "<div><p style='text-indent: 4em'>项目名称：" + projectManageInfo.getProjectTheme() + "</p></div>"
                + "<div><p style='text-indent: 4em'>项目编号：" + projectManageInfo.getProjectNumber() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同名称：" + contractInfo.getContractTopic() + "</p></div>"
                + "<div><p style='text-indent: 4em'>合同编号：" + contractInfo.getContractNo() + "</p></div>"
                + "<div><p style='text-indent: 4em'>客户名称：" + enterpriseInfo.getEnterpriseName() + "</p></div>"
                + "<div><p style='text-indent: 4em'>期次：第" + backMoneyPlanVo.getBmpPeriod() + "期次" + "</p></div>"
                + "<div><p style='text-indent: 2em'>请及时处理以上事项！如已回款请登录公司客户关系管理系统-项目信息-项目列表页面更新信息。</p></div> "
                + "<div><p style='text-indent: 2em'>谢谢！</p></div> "
                + "<div><p style='text-indent: 4em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        //邮件内容
        emailVO.setMailContent(msg);
        emailVO.setEmtilType(EmailType.EMAIL_TYPE_HTML);
        CompletableFuture.runAsync(() -> {
            sentMailFeginService.sentMail(emailVO);
        });
    }

    private String getCopyForUserEmails(List<SysUserEntity> userList) {
        StringBuilder copyForUserEmails = new StringBuilder();           // 抄送人邮箱
        if (!userList.isEmpty()) {      // 根据抄送用户对象拼接抄送人邮箱
            for (SysUserEntity copyForUser : userList) {
                copyForUserEmails.append(copyForUser.getEmail()).append(",");
            }
            // 移除最后一个逗号
            copyForUserEmails.replace(copyForUserEmails.lastIndexOf(","), copyForUserEmails.length() - 1, "");
        }
        return copyForUserEmails.toString();

    }

    /**
     * 生成审批邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期数
     * @return
     */
    private String billingRecordEmailData(String userName,String msgTopic,String approvalCode,String askeUserName,
                                         String contractTopic, String contractNo,
                                         String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统审批路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=crmtodoItems&me=todoApprovalPath'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }

    /**
     * 生成审批邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期次
     * @return
     */
    private String billingRecordEmailData1(String userName,String msgTopic,String approvalCode,String askeUserName,
                                          String contractTopic, String contractNo,
                                          String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }

    private String billingRecordEmailData2(String userName,String msgTopic,String approvalCode,String askeUserName,
                                           String contractTopic, String contractNo,
                                           String contractAmount,String bmpPeriod,String opinion){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批人："+AuthUtils.getUserName()+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批意见："+opinion+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 申请记录 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }



    /**
     * 生成审批邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期数
     * @return
     */
    private String initContractEmailData(String userName,String msgTopic,String approvalCode,String askeUserName,
                                         String contractTopic, String contractNo,
                                         String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统审批路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=crmtodoItems&me=todoApprovalPath'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }
    /**
     * 生成审批邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期数
     * @return
     */
    private String initContractEmailData1(String userName,String msgTopic,String approvalCode,String askeUserName,
                                         String contractTopic, String contractNo,
                                         String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }
    //驳回
    private String initContractEmailData2(String userName,String msgTopic,String approvalCode,String askeUserName,
                                          String contractTopic, String contractNo,
                                          String contractAmount,String bmpPeriod,String opinion){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批人："+AuthUtils.getUserName()+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批意见："+opinion+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>申请开票期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 申请记录 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }
    /**
     * 生成通知邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期次
     * @return
     */
    private String backMoneyRecordEmailData(String userName,String msgTopic,String approvalCode,String askeUserName,
                                         String contractTopic, String contractNo,
                                         String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>回款金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统审批路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=crmtodoItems&me=todoApprovalPath'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }
    /**
     * 生成通知邮件内容
     * @param userName 邮件发送人
     * @param msgTopic 邮件主题
     * @param approvalCode 事项编号
     * @param askeUserName 申请人
     * @param contractTopic 合同名称
     * @param contractNo 合同号
     * @param contractAmount 金额
     * @param bmpPeriod 期数
     * @return
     */
    private String backMoneyRecordEmailData1(String userName,String msgTopic,String approvalCode,String askeUserName,
                                            String contractTopic, String contractNo,
                                            String contractAmount,String bmpPeriod){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请人："+askeUserName+"</p></div>"+
                "<div><p style='text-indent: 2em'>申请时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>回款金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 待办审批 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }
    private String backMoneyRecordEmailData2(String userName,String msgTopic,String approvalCode,String askeUserName,
                                             String contractTopic, String contractNo,
                                             String contractAmount,String bmpPeriod,String opinion){
        String msg =  "<div><p >" + "尊敬的" + userName + "：</p></div>" +
                "<div><p style='text-indent: 2em'>您好，"+msgTopic +"：</p></div>"+
                "<div><p style='text-indent: 2em'>事项编号："+approvalCode+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批人："+AuthUtils.getUserName()+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批意见："+opinion+"</p></div>"+
                "<div><p style='text-indent: 2em'>审批时间："+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同名称："+contractTopic+"</p></div>"+
                "<div><p style='text-indent: 2em'>合同编号："+contractNo+"</p></div>"+
                "<div><p style='text-indent: 2em'>回款金额："+contractAmount+"元</p></div>"+
                "<div><p style='text-indent: 2em'>期次：第"+bmpPeriod+"期</p></div>"+
                "<div><p style='text-indent: 2em'>系统查看路径：客户关系管理系统 - 待办事项 - 申请记录 "+
                "<a href='"+webSitUrl+"/?m=crm&p=todoItems&me=todoApproval'>进入</a></p></div>"+
                "<div><p style='text-indent: 2em'>谢谢！</p></div>"+
                "<div><p style='text-indent: 2em'>说明：该邮件为系统自动发送，请勿回复。</p></div>";
        return msg;
    }

    /**
     * 获取开票申请抄送人
     * @return
     */
    private String queryBillingApplyCC(){
        //获取抄送人
        List<SysUserEntity> userIds = dictionaryService.queryCcUserIdsByCode("billingApplyCC");
        StringBuilder emailList = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            if (userIds.size()-1 == i){
                emailList.append(userIds.get(i).getEmail());
            }else {
                emailList.append(userIds.get(i).getEmail());
                emailList.append(",");
            }
        }
        return emailList.toString();
    }

    /**
     * 获取开票记录抄送人
     * @return
     */
    private String queryBillingRecordCC(){
        //获取抄送人
        List<SysUserEntity> userIds = dictionaryService.queryCcUserIdsByCode("billingRecordCC");
        StringBuilder emailList = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            if (userIds.size()-1 == i){
                emailList.append(userIds.get(i).getEmail());
            }else {
                emailList.append(userIds.get(i).getEmail());
                emailList.append(",");
            }
        }
        return emailList.toString();
    }

    /**
     * 获取回款记录抄送人
     * @return
     */
    private String queryBackMoneyRecordCC(){
        //获取抄送人
        List<SysUserEntity> userIds = dictionaryService.queryCcUserIdsByCode("backMoneyRecordCC");
        StringBuilder emailList = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            if (userIds.size()-1 == i){
                emailList.append(userIds.get(i).getEmail());
            }else {
                emailList.append(userIds.get(i).getEmail());
                emailList.append(",");
            }
        }
        return emailList.toString();
    }

    @Override
    public Boolean judgePeriod(Integer contractId,Integer state, List<Integer> period) {
        //根据合同id查询所有已经申请开票的期次
        List<String> billingApplyPeriod = brAndBmrMapper.getBillingApplyPeriod(contractId,null,state);
        ArrayList<Integer> applyPeriodList = new ArrayList<>();
        for (String s : billingApplyPeriod) {
            for (String s1 : s.split(",")) {
                applyPeriodList.add(Integer.valueOf(s1));
            }
        }
        for (Integer integer : period) {
            for (Integer integer1 : applyPeriodList) {
                    if (integer == integer1){
                        return true;
                    }
            }
        }
        return false;
    }

    @Override
    public Boolean judgePeriodEdit(Integer contractId, Integer billingRecordId,Integer state, List<Integer> period) {
        //根据合同id查询所有已经申请开票的期次
        List<String> billingApplyPeriod = brAndBmrMapper.getBillingApplyPeriod(contractId,billingRecordId,state);
        ArrayList<Integer> applyPeriodList = new ArrayList<>();
        for (String s : billingApplyPeriod) {
            for (String s1 : s.split(",")) {
                applyPeriodList.add(Integer.valueOf(s1));
            }
        }
        for (Integer integer : period) {
            for (Integer integer1 : applyPeriodList) {
                if (integer == integer1){
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 判断回款记录 期次是否重复 -- 修改/创建
     * @param contractId
     * @param bmrId
     * @param period
     * @return
     */
    @Override
    public Boolean judgeBmrPeriod(Integer contractId, Integer bmrId, List<Integer> period) {
        //根据合同id查询所有已经申请开票的期次
        List<String> backMoneyRecordPeriod = brAndBmrMapper.getBackMoneyRecordPeriod(contractId, bmrId);
        ArrayList<Integer> applyPeriodList = new ArrayList<>();
        for (String s : backMoneyRecordPeriod) {
            for (String s1 : s.split(",")) {
                applyPeriodList.add(Integer.valueOf(s1));
            }
        }
        for (Integer integer : period) {
            for (Integer integer1 : applyPeriodList) {
                if (integer == integer1){
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 修改开票记录 回款状态
     */
    public void updateBillingAndBackMoneyIsbm(Integer billId,Integer isBm) {
        //修改开票记录 回款状态
        brAndBmrMapper.updateBillingRecordIsbm(billId,isBm);

    }

    @Override
    public PageUtil<BackMoneyRecordVo> getBmrListByPage(IPage<BackMoneyRecordVo> page, BackMoneyRecordVo backMoneyRecordVo, String orderBy, String token) {
        IPage<BackMoneyRecordVo> bmrListByPage = new Page<>();

        ApprovalVO approvalVO = new ApprovalVO();
        approvalVO.setApprovalType(29);
        List<ApprovalVO>  appList = new ArrayList<>();
        Boolean aBoolean = true;
        if ("todo".equals(backMoneyRecordVo.getParamsType())){
            appList = approvalService.queryApprovalByPage(approvalVO);
        }else if ("done".equals(backMoneyRecordVo.getParamsType())){
            appList = approvalService.queryApprovalDoneRecordByType(approvalVO);
        }else if ("record".equals(backMoneyRecordVo.getParamsType())){
            appList = approvalService.queryApprovalRecordByType(approvalVO,token);
        }else {
            aBoolean = false;
            List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("backMoneyRecord");
            Boolean result = false;
            for (SysUserEntity item:authUserIList) {
                if (item.getUserId().equals(AuthUtils.getUserId())){
                    result = true;
                    break;
                }
            }
            if (!result){
                if (AuthUtils.getUserId().equals(backMoneyRecordVo.getCreator()) || backMoneyRecordVo.getCreator() == null) {
                    backMoneyRecordVo.setCreator(AuthUtils.getUserId());
                } else {
                    backMoneyRecordVo.setCreator(-1);
                }
            }
            bmrListByPage = brAndBmrMapper.getBmrListByPage(page, backMoneyRecordVo, orderBy);
        }
        if (aBoolean){
             if (appList != null && appList.size() > 0){
                ArrayList<Integer> arrayList = new ArrayList<>();
                for (ApprovalVO item:appList) {
                    arrayList.add(item.getApprovalId());
                }
                backMoneyRecordVo.setApprovalIdList(arrayList);
                bmrListByPage = brAndBmrMapper.getBmrApplyListByPage(page, backMoneyRecordVo, orderBy);
            } else {
                return new PageUtil(bmrListByPage);
            }
        }

        List<BackMoneyRecordVo> records = bmrListByPage.getRecords();

        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("isBilling");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();
        if(!records.isEmpty()){
            BigDecimal bmrMoneyPage  = new BigDecimal("0");
            for (BackMoneyRecordVo item: records) {
                if(!StringUtils.isEmpty(item.getBmrMoney())){
                    bmrMoneyPage= bmrMoneyPage.add(new BigDecimal(item.getBmrMoney()));
                }
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                    if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                        item.setIsBmName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBilling")) {
                    if(dictionaryLookupItemVO.getSort().equals(item.getIsBilling())){
                        item.setIsBillingName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                String[] split = item.getBmrPeriod().split(",");
                String bmrPeriod = "";
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                    for (String split1:split) {
                        if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                            bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + "，";
                        }
                    }
                }
                if (!bmrPeriod.equals("")){
                    String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                    item.setBmrPeriod(substring);
                }

                for (Map item1:approvalStatus) {
                    if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                        item.setApprovalStatusName((String) item1.get("itemName"));
                        break;
                    }
                }

                for (SysUserEntity item2:allUsers) {
                    if(item2.getUserId().equals(item.getLiableId())){
                        item.setLiableName(item2.getLoginName());
                        item.setAccount(item2.getAccount());
                        break;
                    }
                }
            }
            records.get(0).setBmrMoneyPage(String.valueOf(bmrMoneyPage));
            bmrListByPage.setRecords(records);
        }
        return new PageUtil(bmrListByPage);
    }


    @Override
    public PageUtil<BillingApplyVo> getBarListByPage(IPage<BillingApplyVo> page, BillingApplyVo billingApplyVo, String orderBy, String token) {

        IPage<BillingApplyVo> barListByPage = new Page<>();

        ApprovalVO approvalVO = new ApprovalVO();
        approvalVO.setApprovalType(26);
        List<ApprovalVO>  appList = new ArrayList<>();
        Boolean aBoolean = true;
        if ("todo".equals(billingApplyVo.getParamsType())){
            appList = approvalService.queryApprovalByPage(approvalVO);
        }else if ("done".equals(billingApplyVo.getParamsType())){
            appList = approvalService.queryApprovalDoneRecordByType(approvalVO);
        }else if ("record".equals(billingApplyVo.getParamsType())){
            appList = approvalService.queryApprovalRecordByType(approvalVO,token);
        }else {
            List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("billingApplyRecord");
            Boolean result = false;
            for (SysUserEntity item:authUserIList) {
                if (item.getUserId().equals(AuthUtils.getUserId())){
                    result = true;
                    break;
                }
            }
            if (!result){
                if (AuthUtils.getUserId().equals(billingApplyVo.getCreator()) || billingApplyVo.getCreator() == null) {
                    billingApplyVo.setCreator(AuthUtils.getUserId());
                } else {
                    billingApplyVo.setCreator(-1);
                }
            }
            aBoolean = false;
            barListByPage = brAndBmrMapper.getBarListByPage(page, billingApplyVo, orderBy);
        }
        if (aBoolean){
             if (appList != null && appList.size() > 0){
                ArrayList<Integer> arrayList = new ArrayList<>();
                for (ApprovalVO item:appList) {
                    arrayList.add(item.getApprovalId());
                }
                billingApplyVo.setApprovalIdList(arrayList);
                barListByPage = brAndBmrMapper.getBarApplyListByPage(page, billingApplyVo, orderBy);
            } else {
                return new PageUtil(barListByPage);
            }
        }
        List<BillingApplyVo> records = barListByPage.getRecords();
        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("billType");
        codes.add("billingCompany");
        codes.add("isTax");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();
        if(!records.isEmpty()){
            BigDecimal billMoneyPage = new BigDecimal("0");
            BigDecimal taxMoneyPage = new BigDecimal("0");
            for (BillingApplyVo item: records) {
                if(!StringUtils.isEmpty(item.getBillMoney())){
                    billMoneyPage = billMoneyPage.add(new BigDecimal(item.getBillMoney()));
                }
                if(!StringUtils.isEmpty(item.getTaxMoney())){
                    taxMoneyPage = taxMoneyPage.add(new BigDecimal(item.getTaxMoney()));
                }
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                    if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                        item.setIsBmName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billType")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getBillType().toString())){
                        item.setBillTypeName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isTax")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getIsTax().toString())){
                        item.setIsTaxName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billingCompany")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getBillingCompany().toString())){
                        item.setBillingCompanyName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }
                String[] split = item.getPeriodStr().split(",");
                String bmrPeriod = "";
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                    for (String split1:split) {
                        if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                            bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + "，";
                        }
                    }
                }
                if (!bmrPeriod.equals("")){
                    String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                    item.setPeriodStr(substring);
                }

                for (Map item1:approvalStatus) {
                    if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                        item.setApprovalStatusName((String) item1.get("itemName"));
                        break;
                    }
                }

                for (SysUserEntity item2:allUsers) {
                    if(item2.getUserId().equals(item.getLiableId())){
                        item.setLiableName(item2.getLoginName());
                        item.setAccount(item2.getAccount());
                        break;
                    }
                }
            }
            records.get(0).setTaxMoneyPage(String.valueOf(taxMoneyPage));
            records.get(0).setBillMoneyPage(String.valueOf(billMoneyPage));
            barListByPage.setRecords(records);
        }
        return new PageUtil(barListByPage);
    }

    @Override
    public PageUtil<BillingRecordVo> getBriListByPage(IPage<BillingRecordVo> page, BillingRecordVo billingRecordVo, String orderBy, String token) {
        IPage<BillingRecordVo> briListByPage = new Page<>();

        ApprovalVO approvalVO = new ApprovalVO();
        approvalVO.setApprovalType(28);
        List<ApprovalVO>  appList = new ArrayList<>();
        Boolean aBoolean = true;
        if ("todo".equals(billingRecordVo.getParamsType())){
            appList = approvalService.queryApprovalByPage(approvalVO);
        }else if ("done".equals(billingRecordVo.getParamsType())){
            appList = approvalService.queryApprovalDoneRecordByType(approvalVO);
        }else if ("record".equals(billingRecordVo.getParamsType())){
            appList = approvalService.queryApprovalRecordByType(approvalVO,token);
        }else {
            aBoolean = false;
            List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("billingRecord");
            Boolean result = false;
            for (SysUserEntity item:authUserIList) {
                if (item.getUserId().equals(AuthUtils.getUserId())){
                    result = true;
                    break;
                }
            }
            if (!result){
                if (AuthUtils.getUserId().equals(billingRecordVo.getCreator()) || billingRecordVo.getCreator() == null) {
                    billingRecordVo.setCreator(AuthUtils.getUserId());
                } else {
                    billingRecordVo.setCreator(-1);
                }
            }
            briListByPage = brAndBmrMapper.getBriListByPage(page, billingRecordVo, orderBy);
        }
        if (aBoolean){
             if (appList != null && appList.size() > 0){
                ArrayList<Integer> arrayList = new ArrayList<>();
                for (ApprovalVO item:appList) {
                    arrayList.add(item.getApprovalId());
                }
                billingRecordVo.setApprovalIdList(arrayList);
                briListByPage = brAndBmrMapper.getBriApplyListByPage(page, billingRecordVo, orderBy);
            } else {
                return new PageUtil(briListByPage);
            }
        }

        List<BillingRecordVo> records = briListByPage.getRecords();
        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("billType");
        codes.add("billingCompany");
        codes.add("isTax");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();
        if(!records.isEmpty()){
            BigDecimal billMoneyPage = new BigDecimal("0");
            BigDecimal taxMoneyPage = new BigDecimal("0");
            for (BillingRecordVo item: records) {
                if(!StringUtils.isEmpty(item.getBillMoney())){
                    billMoneyPage = billMoneyPage.add(new BigDecimal(item.getBillMoney()));
                }
                if(!StringUtils.isEmpty(item.getTaxMoney())){
                    taxMoneyPage = taxMoneyPage.add(new BigDecimal(item.getTaxMoney()));
                }
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                    if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                        item.setIsBmName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billType")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getBillType().toString())){
                        item.setBillTypeName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isTax")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getIsTax().toString())){
                        item.setIsTaxName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }

                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billingCompany")) {
                    if(dictionaryLookupItemVO.getItemCode().equals(item.getBillingCompany().toString())){
                        item.setBillingCompanyName(dictionaryLookupItemVO.getItemName());
                        break;
                    }
                }
                String[] split = item.getPeriod().split(",");
                String bmrPeriod = "";
                for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                    for (String split1:split) {
                        if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                            bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + "，";
                        }
                    }
                }
                if (!bmrPeriod.equals("")){
                    String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                    item.setPeriod(substring);
                }

                for (Map item1:approvalStatus) {
                    if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                        item.setApprovalStatusName((String) item1.get("itemName"));
                        break;
                    }
                }

                for (SysUserEntity item2:allUsers) {
                    if(item2.getUserId().equals(item.getLiableId())){
                        item.setLiableName(item2.getLoginName());
                        item.setAccount(item2.getAccount());
                        break;
                    }
                }
            }
            records.get(0).setTaxMoneyPage(String.valueOf(taxMoneyPage));
            records.get(0).setBillMoneyPage(String.valueOf(billMoneyPage));
            briListByPage.setRecords(records);
        }
        return new PageUtil(briListByPage);
    }

    @Override
    public void exportBar(HttpServletResponse response, BillingApplyVo billingApplyVo, String token) throws Exception {
        List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("billingApplyRecord");
        Boolean result = false;
        for (SysUserEntity item:authUserIList) {
            if (item.getUserId().equals(AuthUtils.getUserId())){
                result = true;
                break;
            }
        }
        if (!result){
            if (AuthUtils.getUserId().equals(billingApplyVo.getCreator()) || billingApplyVo.getCreator() == null) {
                billingApplyVo.setCreator(AuthUtils.getUserId());
            } else {
                billingApplyVo.setCreator(-1);
            }
        }
        List<BillingApplyVo> barList = brAndBmrMapper.getBarList(billingApplyVo);

        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("billType");
        codes.add("billingCompany");
        codes.add("isTax");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();

        for (BillingApplyVo item: barList) {

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                    item.setIsBmName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billType")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getBillType().toString())){
                    item.setBillTypeName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isTax")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getIsTax().toString())){
                    item.setIsTaxName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billingCompany")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getBillingCompany().toString())){
                    item.setBillingCompanyName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }
            String[] split = item.getPeriodStr().split(",");
            String bmrPeriod = "";
            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                for (String split1:split) {
                    if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                        bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + ",";
                    }
                }
            }
            if (!bmrPeriod.equals("")){
                String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                item.setPeriodStr(substring);
            }

            for (Map item1:approvalStatus) {
                if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                    item.setApprovalStatusName((String) item1.get("itemName"));
                    break;
                }
            }

            for (SysUserEntity item2:allUsers) {
                if(item2.getUserId().equals(item.getLiableId())){
                    item.setLiableName(item2.getLoginName());
                    item.setAccount(item2.getAccount());
                    break;
                }
            }
        }


        int i = 1;
        for (BillingApplyVo item: barList) {
            item.setBillingRecordId(i);
//            item.setBillingDateStr(String.format("%tY-%<tm-%<td",item.getBillingDate()));
            i++;
        }

        //获取yml模板位置
        YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
        String path = "application.yml";
        factoryBean.setResources(new ClassPathResource(path));
        Properties properties = factoryBean.getObject();
        String contractTemplatePath = String.valueOf(properties.get("report.billingApplyRecordTemplate"));

        //依据根目录获取模板位置
        TemplateExportParams params = new TemplateExportParams(contractTemplatePath);
        Map<String, Object> map = new HashMap<>();
        map.put("vo",barList);
        ReportUtils.exportExcel(params,map,"开票申请列表",response);
    }

    @Override
    public void exportBmr(HttpServletResponse response, BackMoneyRecordVo backMoneyRecordVo, String token) throws Exception {
        List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("backMoneyRecord");
        Boolean result = false;
        for (SysUserEntity item:authUserIList) {
            if (item.getUserId().equals(AuthUtils.getUserId())){
                result = true;
                break;
            }
        }
        if (!result){
            if (AuthUtils.getUserId().equals(backMoneyRecordVo.getCreator()) || backMoneyRecordVo.getCreator() == null) {
                backMoneyRecordVo.setCreator(AuthUtils.getUserId());
            } else {
                backMoneyRecordVo.setCreator(-1);
            }
        }
        List<BackMoneyRecordVo> bmrListByPage = brAndBmrMapper.getBmrList(backMoneyRecordVo);

        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("isBilling");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();

        for (BackMoneyRecordVo item: bmrListByPage) {

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                    item.setIsBmName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBilling")) {
                if(dictionaryLookupItemVO.getSort().equals(item.getIsBilling())){
                    item.setIsBillingName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            String[] split = item.getBmrPeriod().split(",");
            String bmrPeriod = "";
            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                for (String split1:split) {
                    if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                        bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + ",";
                    }
                }
            }
            if (!bmrPeriod.equals("")){
                String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                item.setBmrPeriod(substring);
            }

            for (Map item1:approvalStatus) {
                if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                    item.setApprovalStatusName((String) item1.get("itemName"));
                    break;
                }
            }

            for (SysUserEntity item2:allUsers) {
                if(item2.getUserId().equals(item.getLiableId())){
                    item.setLiableName(item2.getLoginName());
                    item.setAccount(item2.getAccount());
                    break;
                }
            }
        }


        int i = 1;
        for (BackMoneyRecordVo item: bmrListByPage) {
            item.setBmrId(i);
            item.setBmrDateStr(String.format("%tY-%<tm-%<td",item.getBmrDate()));
            i++;
        }

        //获取yml模板位置
        YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
        String path = "application.yml";
        factoryBean.setResources(new ClassPathResource(path));
        Properties properties = factoryBean.getObject();
        String contractTemplatePath = String.valueOf(properties.get("report.backMoneyRecordsTemplate"));

        //依据根目录获取模板位置
        TemplateExportParams params = new TemplateExportParams(contractTemplatePath);
        Map<String, Object> map = new HashMap<>();
        map.put("vo",bmrListByPage);
        ReportUtils.exportExcel(params,map,"回款记录列表",response);
    }


    @Override
    public void exportBri(HttpServletResponse response, BillingRecordVo billingRecordVo, String token) throws Exception {
        List<SysUserEntity> authUserIList = dictionaryService.queryAuthUserIdsByCode("billingRecord");
        Boolean result = false;
        for (SysUserEntity item:authUserIList) {
            if (item.getUserId().equals(AuthUtils.getUserId())){
                result = true;
                break;
            }
        }
        if (!result){
            if (AuthUtils.getUserId().equals(billingRecordVo.getCreator()) || billingRecordVo.getCreator() == null) {
                billingRecordVo.setCreator(AuthUtils.getUserId());
            } else {
                billingRecordVo.setCreator(-1);
            }
        }
        List<BillingRecordVo> barList = brAndBmrMapper.getBriList(billingRecordVo);

        //crm 字典
        List<String> codes = new ArrayList<>();
        codes.add("isBm");
        codes.add("billType");
        codes.add("billingCompany");
        codes.add("isTax");
        codes.add("paymentPeriodNum");
        // auth 字典
        List<String> dictCodes = new ArrayList<>();
        dictCodes.add("approvalStatus");
        LinkedHashMap linkedHashMap = (LinkedHashMap) feginService.queryDictionaryLookupInfo("crm", dictCodes).get("result");
        List<Map> approvalStatus = (List)linkedHashMap.get("approvalStatus");
        Map<String, List<DictionaryLookupItemVO>> stringListMap = dictionaryService.queryDictionaryLookupInfo(null, codes);
        // 获取所有人信息
        List<SysUserEntity> allUsers = feginService.getUserIgnoreFlag(token).getResult();

        for (BillingRecordVo item: barList) {

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isBm")) {
                if(dictionaryLookupItemVO.getSort().equals(item.getIsBm())){
                    item.setIsBmName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billType")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getBillType().toString())){
                    item.setBillTypeName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("isTax")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getIsTax().toString())){
                    item.setIsTaxName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }

            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("billingCompany")) {
                if(dictionaryLookupItemVO.getItemCode().equals(item.getBillingCompany().toString())){
                    item.setBillingCompanyName(dictionaryLookupItemVO.getItemName());
                    break;
                }
            }
            String[] split = item.getPeriod().split(",");
            String bmrPeriod = "";
            for (DictionaryLookupItemVO dictionaryLookupItemVO:stringListMap.get("paymentPeriodNum")) {
                for (String split1:split) {
                    if (dictionaryLookupItemVO.getItemCode().equals(split1)){
                        bmrPeriod =  bmrPeriod + dictionaryLookupItemVO.getItemName() + ",";
                    }
                }
            }
            if (!bmrPeriod.equals("")){
                String substring = bmrPeriod.substring(0, bmrPeriod.length() - 1);
                item.setPeriod(substring);
            }

            for (Map item1:approvalStatus) {
                if(item1.get("itemCode").equals(item.getApprovalStatus() + "")){
                    item.setApprovalStatusName((String) item1.get("itemName"));
                    break;
                }
            }

            for (SysUserEntity item2:allUsers) {
                if(item2.getUserId().equals(item.getLiableId())){
                    item.setLiableName(item2.getLoginName());
                    item.setAccount(item2.getAccount());
                    break;
                }
            }
        }

        int i = 1;
        for (BillingRecordVo item: barList) {
            item.setBillingRecordId(i);
            item.setBillingDateStr(String.format("%tY-%<tm-%<td",item.getBillingDate()));
            i++;
        }

        //获取yml模板位置
        YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean();
        String path = "application.yml";
        factoryBean.setResources(new ClassPathResource(path));
        Properties properties = factoryBean.getObject();
        String contractTemplatePath = String.valueOf(properties.get("report.billingRecordTemplate"));

        //依据根目录获取模板位置
        TemplateExportParams params = new TemplateExportParams(contractTemplatePath);
        Map<String, Object> map = new HashMap<>();
        map.put("vo",barList);
        ReportUtils.exportExcel(params,map,"开票列表",response);
    }

    /**
     * 撤回时根据审批ID修改回款计划申请金额
     * @param approvalId
     */
    @Override
    public void updateBackMoneyBillMoneyByApprovalId(Integer approvalId) {
        backupBBM(approvalId,AuthUtils.getUserId());
    }

    @Override
    public void updateBilling(Integer approvalId) {
        brAndBmrMapper.updateBilling(approvalId);
    }

    /**
     * 获取剩余金额（根据计划id）
     * @param bmpId
     * @return
     */
    @Override
    public BackBillingMoneyVo getResidualMoneybyBmpId(Integer bmpId) {
        BackBillingMoneyVo backBillingMoneyVo = new BackBillingMoneyVo();
        //获取计划金额
        String bmpMoney = brAndBmrMapper.getBackMoneyBybmpId(bmpId);
        BigDecimal bmpMoneyBigm = new BigDecimal(bmpMoney);
        //计算剩余金额
        List<String> moneyList = brAndBmrMapper.getMoney(bmpId);
        String residualMoney;
        if (moneyList.size()>0){
            List<BigDecimal> residuaList = moneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            BigDecimal reduce = residuaList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            residualMoney = bmpMoneyBigm.subtract(reduce).toString();
        }else{
            residualMoney = bmpMoney ;
        }
        backBillingMoneyVo.setBmpMoney(bmpMoney);
        backBillingMoneyVo.setResidualMoney(residualMoney);
        return backBillingMoneyVo;
    }

    /**
     * 根据开票申请id查询开票申请详情
     * @param billingRecordId
     * @return
     */
    @Override
    public BillingApplyDto getBillingApply(Integer billingRecordId) {
        return brAndBmrMapper.getBillingApply(billingRecordId);
    }

    @Override
    public void saveBackBillingMoney(List<BackBillingMoneyVo> backBillingMoneylist) {
        Integer approvalId = backBillingMoneylist.get(0).getApprovalId();
        brAndBmrMapper.saveBackBillingMoney(backBillingMoneylist);
        ApprovalVO approvalVO = approvalService.queryApprovalByAppID(approvalId);
        if(approvalVO.getApprovalStatus()==1 && approvalVO.getApprovalType() == 28){
            //返填回款计划开票信息
            List<BackBillingMoneyVo> backBillingMoneys = brAndBmrMapper.getBackBillingMoneyByApprovalId(approvalId);
            for (BackBillingMoneyVo backBillingMoney : backBillingMoneys){
                Integer bmpId = backBillingMoney.getBmpId();
                //获取bmp信息
                BackMoneyPlanVo backMoneyPlan = brAndBmrMapper.getBackMoneyPlanBackByBmpId(bmpId);
                if(Double.parseDouble(backMoneyPlan.getBmpMoney())== Double.parseDouble(backBillingMoney.getMoney())){
                    backMoneyPlan.setIsBilling(1);
                }else if(Double.parseDouble(backBillingMoney.getMoney()) < Double.parseDouble(backMoneyPlan.getBmpMoney())
                        && Double.parseDouble(backBillingMoney.getMoney()) > 0){
                    backMoneyPlan.setIsBilling(2);
                }else {
                    backMoneyPlan.setIsBilling(0);
                }
                brAndBmrMapper.updateBmpIsbilling(backMoneyPlan);
            }
        }
    }

    @Override
    public List<BackBillingMoneyVo> getBackBillingMoneyByApprovalId(Integer approvalId) {

        List<BackBillingMoneyVo> backBillingMoneylist = brAndBmrMapper.getBackBillingMoneyByApprovalId(approvalId);
        if (backBillingMoneylist.size()==0){
            List<BackBillingMoneyVo> backBillingMoneyBackList = brAndBmrMapper.getBackBillingMoneyBackByApprovalId(approvalId);
            for (BackBillingMoneyVo backBillingMoneyVo : backBillingMoneyBackList) {
                String bmpMoney = brAndBmrMapper.getBackMoneyBybmpId(backBillingMoneyVo.getBmpId());
                BigDecimal bmpMoneyBigm = new BigDecimal(bmpMoney);
                List<String> moneyList = brAndBmrMapper.getMoney(backBillingMoneyVo.getBmpId());
                List<String> alrBackMoneyList = brAndBmrMapper.getAlrBackMoneyBybmpId(backBillingMoneyVo.getBmpId());
                //剩余开票金额
                String residualMoney;
                //剩余回款金额
                String residualBackMoney;
                if (moneyList.size()>0){
                    List<BigDecimal> residuaList = moneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
                    BigDecimal reduce = residuaList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    residualMoney = bmpMoneyBigm.subtract(reduce).toString();
                }else{
                    residualMoney = bmpMoney ;
                }
                if(alrBackMoneyList.size() > 0){
                    List<BigDecimal> alrBackMoneyBig = alrBackMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
                    BigDecimal alrBackMoney = alrBackMoneyBig.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    residualBackMoney = bmpMoneyBigm.subtract(alrBackMoney).toString();

                }else{
                    residualBackMoney = bmpMoney;
                }
                backBillingMoneyVo.setBmpMoney(bmpMoney);
                backBillingMoneyVo.setResidualMoney(residualMoney);
                backBillingMoneyVo.setResidualBackMoney(residualBackMoney);
            }
            return backBillingMoneyBackList;
        }else{
            for (BackBillingMoneyVo backBillingMoneyVo : backBillingMoneylist) {
                String bmpMoney = brAndBmrMapper.getBackMoneyBybmpId(backBillingMoneyVo.getBmpId());
                if(StringUtils.isEmpty(bmpMoney)){
                    bmpMoney = "0";
                }
                BigDecimal bmpMoneyBigm = new BigDecimal(bmpMoney);
                List<String> moneyList = brAndBmrMapper.getMoney(backBillingMoneyVo.getBmpId());
                List<String> alrBackMoneyList = brAndBmrMapper.getAlrBackMoneyBybmpId(backBillingMoneyVo.getBmpId());
                //剩余开票金额
                String residualMoney;
                //剩余回款金额
                String residualBackMoney;
                if (moneyList.size()>0){
                    List<BigDecimal> residuaList = moneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
                    BigDecimal reduce = residuaList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    residualMoney = bmpMoneyBigm.subtract(reduce).toString();
                }else{
                    residualMoney = bmpMoney ;
                }
                if(alrBackMoneyList.size() > 0){
                    List<BigDecimal> alrBackMoneyBig = alrBackMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
                    BigDecimal alrBackMoney = alrBackMoneyBig.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                    residualBackMoney = bmpMoneyBigm.subtract(alrBackMoney).toString();

                }else{
                    residualBackMoney = bmpMoney;
                }
                backBillingMoneyVo.setBmpMoney(bmpMoney);
                backBillingMoneyVo.setResidualMoney(residualMoney);
                backBillingMoneyVo.setResidualBackMoney(residualBackMoney);
             }
            return backBillingMoneylist;
        }
    }
    /**
     * 根据回款记录id查询回款记录详情
     * @param bmrId
     * @return
     */
    @Override
    public BackMoneyRecordVo getBackMoneyRecord(Integer bmrId) {
        return brAndBmrMapper.getBackMoneyRecord(bmrId);
    }

    @Override
    public ShowMoneyVo getPlanShowMoney(Integer bmpId) {
        ShowMoneyVo showMoneyVo = new ShowMoneyVo();
        //计算申请金额
        List<BackBillingMoneyVo> backBillingMoneyList = brAndBmrMapper.getBackBillingMoneyByBmpId(bmpId);
        ArrayList<String> bmpMoneyList = new ArrayList<>();
        ArrayList<String> receiveMoneyList = new ArrayList<>();
        ArrayList<String> residualMoneyList = new ArrayList<>();
        for (BackBillingMoneyVo backBillingMoneyVo : backBillingMoneyList) {
            if (    backBillingMoneyVo.getBillId() != null
                    && backBillingMoneyVo.getBillRecordId() == null
                    && backBillingMoneyVo.getBackMoneyId() == null){
                bmpMoneyList.add(backBillingMoneyVo.getMoney());
            }else if (backBillingMoneyVo.getBillId() == null
                    && backBillingMoneyVo.getBillRecordId() != null
                    && backBillingMoneyVo.getBackMoneyId() == null
            ){
                receiveMoneyList.add(backBillingMoneyVo.getMoney());
            }else  if (backBillingMoneyVo.getBillId() == null
                    && backBillingMoneyVo.getBillRecordId() == null
                    && backBillingMoneyVo.getBackMoneyId() != null){
                residualMoneyList.add(backBillingMoneyVo.getMoney());
            }
        }
        //计算申请金额
        if (bmpMoneyList.size()>0){
            List<BigDecimal> bmpMoneyListB = bmpMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            String bmpMoney = bmpMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();
            showMoneyVo.setBmpMoney(bmpMoney);
        }else{
            showMoneyVo.setBmpMoney("0.00");
        }

        //计算开票金额
        if (receiveMoneyList.size()>0){
            List<BigDecimal> receiveMoneyListB = receiveMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            String receiveMoney = receiveMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();
            showMoneyVo.setReceiveMoney(receiveMoney);
        }else{
            showMoneyVo.setReceiveMoney("0.00");
        }

        //计算回款金额
        if (residualMoneyList.size()>0){
            List<BigDecimal> residualMoneyListB = residualMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            String residualMoney = residualMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add).toString();
            showMoneyVo.setResidualMoney(residualMoney);
        }else{
            showMoneyVo.setResidualMoney("0.00");
        }
        return showMoneyVo;
    }

    @Override
    public BillingRecordVo getBillingApplyisNoChoose(Integer billingRecordId) {
        return brAndBmrMapper.getBillingApplyisNoChoose(billingRecordId);
    }

    @Override
    public BillingRecordVo getBillingRecordisNoChoose(Integer billingRecordId) {
        return brAndBmrMapper.getBillingRecordisNoChoose(billingRecordId);
    }

    /**
     * 根据回款计划ID查询所有相关金额（已回、未回、开票回款金额）
     * @param bmpId
     * @return
     */
    @Override
    public Map<String, String> getAllPageShowMoneybyBmpId(Integer bmpId) {
        HashMap<String, String> allPageShowMoneyMap = new HashMap<>();
        //获取计划金额
        String bmpMoney = brAndBmrMapper.getBackMoneyBybmpId(bmpId);
        allPageShowMoneyMap.put("planMoney",bmpMoney);
        BigDecimal bmpMoneyBigm = new BigDecimal(bmpMoney);

        //计算申请金额
        List<BackBillingMoneyVo> backBillingMoneyList = brAndBmrMapper.getBackBillingMoneyByBmpId(bmpId);
        //申请开票金额
        ArrayList<String> bmpMoneyList = new ArrayList<>();
        //开票记录金额
        ArrayList<String> receiveMoneyList = new ArrayList<>();
        //回款记录金额
        ArrayList<String> residualMoneyList = new ArrayList<>();
        for (BackBillingMoneyVo backBillingMoneyVo : backBillingMoneyList) {
            if (    backBillingMoneyVo.getBillId() != null
                    && backBillingMoneyVo.getBillRecordId() == null
                    && backBillingMoneyVo.getBackMoneyId() == null){
                bmpMoneyList.add(backBillingMoneyVo.getMoney());
            }else if (backBillingMoneyVo.getBillId() == null
                    && backBillingMoneyVo.getBillRecordId() != null
                    && backBillingMoneyVo.getBackMoneyId() == null
            ){
                receiveMoneyList.add(backBillingMoneyVo.getMoney());
            }else  if (backBillingMoneyVo.getBillId() == null
                    && backBillingMoneyVo.getBillRecordId() == null
                    && backBillingMoneyVo.getBackMoneyId() != null){
                residualMoneyList.add(backBillingMoneyVo.getMoney());
            }
        }
        //计算申请金额
        if (bmpMoneyList.size()>0){
            List<BigDecimal> bmpMoneyListB = bmpMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            BigDecimal bmpMoneyListBig = bmpMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

            String residualPlanMoney = bmpMoneyBigm.subtract(bmpMoneyListBig).toString();
            String billApplyMoney = bmpMoneyListBig.toString();
            allPageShowMoneyMap.put("billApplyMoney",billApplyMoney);
            //计算剩余申请金额
            allPageShowMoneyMap.put("residualPlanMoney",residualPlanMoney);
        }else{
            allPageShowMoneyMap.put("billApplyMoney","0.00");
            allPageShowMoneyMap.put("residualPlanMoney",bmpMoney);
        }

        //计算开票金额
        if (receiveMoneyList.size()>0){
            List<BigDecimal> receiveMoneyListB = receiveMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            BigDecimal receiveMoneyListBig = receiveMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

            String residualRecordMoney = bmpMoneyBigm.subtract(receiveMoneyListBig).toString();
            String billRecordMoney = receiveMoneyListBig.toString();
            allPageShowMoneyMap.put("billRecordMoney",billRecordMoney);
            //计算剩余开票金额
            allPageShowMoneyMap.put("residualRecordMoney",residualRecordMoney);
        }else{
            allPageShowMoneyMap.put("billRecordMoney","0.00");
            allPageShowMoneyMap.put("residualRecordMoney",bmpMoney);
        }

        //计算回款金额
        if (residualMoneyList.size()>0){
            List<BigDecimal> residualMoneyListB = residualMoneyList.stream().filter(Objects::nonNull).map(BigDecimal::new).collect(Collectors.toList());
            BigDecimal residualMoneyListBig = residualMoneyListB.stream().reduce(BigDecimal.ZERO, BigDecimal::add);

            String residualBackMoney = bmpMoneyBigm.subtract(residualMoneyListBig).toString();
            String alrBackMoney = residualMoneyListBig.toString();
            allPageShowMoneyMap.put("alrBackMoney",alrBackMoney);
            //计算剩余回款金额
            allPageShowMoneyMap.put("residualBackMoney",residualBackMoney);
        }else{
            allPageShowMoneyMap.put("alrBackMoney","0.00");
            allPageShowMoneyMap.put("residualBackMoney",bmpMoney);
        }
        return allPageShowMoneyMap;
    }
}
